JUnit ব্যবহার করে এনভায়রনমেন্ট ভেরিয়েবলের উপর নির্ভরশীল কোড কীভাবে পরীক্ষা করবেন?


139

আমার কাছে জাভা কোডের একটি অংশ রয়েছে যা একটি পরিবেশের পরিবর্তনশীল ব্যবহার করে এবং কোডটির আচরণ এই ভেরিয়েবলের মানের উপর নির্ভর করে। আমি এই কোডটি পরিবেশের ভেরিয়েবলের বিভিন্ন মান সহ পরীক্ষা করতে চাই। আমি কীভাবে এটি ইউনাইটে করতে পারি?

আমি জাভাতে সাধারণভাবে পরিবেশের পরিবর্তনশীলগুলি সেট করার কিছু উপায় দেখেছি , তবে আমি এর ইউনিট পরীক্ষার দিকটি সম্পর্কে আরও আগ্রহী, বিশেষত বিবেচনা করে যে পরীক্ষাগুলি একে অপরের সাথে হস্তক্ষেপ করা উচিত নয়।


যেহেতু এটি পরীক্ষার জন্য, তাই সিস্টেম বিধি ইউনিট পরীক্ষা নিয়মটি বর্তমানে সেরা উত্তর হতে পারে।
আতিফম

3
JUnit 5 ব্যবহার করার সময় কেবল একই প্রশ্নে আগ্রহী তাদের জন্য: স্ট্যাকওভারফ্লো.
ফিলিপ মার্টিনস মেলো

উত্তর:


199

লাইব্রেরি সিস্টেম বিধি পরিবেশের ভেরিয়েবলগুলি সেট করার জন্য একটি JUnit বিধি সরবরাহ করে।

import org.junit.contrib.java.lang.system.EnvironmentVariables;

public class EnvironmentVariablesTest {
  @Rule
  public final EnvironmentVariables environmentVariables
    = new EnvironmentVariables();

  @Test
  public void setEnvironmentVariable() {
    environmentVariables.set("name", "value");
    assertEquals("value", System.getenv("name"));
  }
}

দাবি অস্বীকার: আমি সিস্টেম বিধিগুলির লেখক।


1
আমি এটি @ ক্লাসআরুল হিসাবে ব্যবহার করছি, ব্যবহারের পরে আমার কি এটি পুনরায় সেট করার বা পরিষ্কার করার দরকার আছে, যদি হ্যাঁ তবে কীভাবে?
মৃৎঞ্জয়

আপনার দরকার নেই। ক্লাসে সমস্ত পরীক্ষা চালানো হওয়ার পরে আসল পরিবেশের ভেরিয়েবলগুলি নিয়ম দ্বারা স্বয়ংক্রিয়ভাবে পুনরায় সেট হয়।
স্টিফান বার্কনার

এই পদ্ধতিরটি কেবল JUnit 4 বা উচ্চতর সংস্করণের জন্য কাজ করে। JUnit 3 বা নিম্ন সংস্করণের জন্য প্রস্তাবিত নয় বা আপনি JUnit 4 এবং JUnit 3. মেশান যদি না হয়
আরএলডি

2
import org.junit.contrib.java.lang.system.EnvironmentVariables;com.github.stefanbirkner:system-rulesআপনার প্রকল্পে নির্ভরতা যুক্ত করতে হবে । এটি মাভেনসেন্ট্রালে উপলব্ধ।
জিন বব

2
নির্ভরতা যুক্ত করার জন্য এখানে নির্দেশাবলী দেওয়া হয়েছে: stefanbirkner.github.io/system-rules/download.html
গার্নিয়ার

77

সাধারণ সমাধান হ'ল এমন একটি ক্লাস তৈরি করা যা এই পরিবেশগত পরিবর্তনশীলটির অ্যাক্সেস পরিচালনা করে, যা আপনি নিজের পরীক্ষার ক্লাসে উপহাস করতে পারেন।

public class Environment {
    public String getVariable() {
        return System.getenv(); // or whatever
    }
}

public class ServiceTest {
    private static class MockEnvironment {
        public String getVariable() {
           return "foobar";
        }
    }

    @Test public void testService() {
        service.doSomething(new MockEnvironment());
    }
}

পরীক্ষার অধীন শ্রেণিটি তারপরে সরাসরি সিস্টেম.জেটেনভ () থেকে নয়, পরিবেশ বর্গ ব্যবহার করে পরিবেশের পরিবর্তনশীল হয়ে ওঠে।


1
আমি জানি এই প্রশ্নটি পুরানো, তবে আমি বলতে চাই যে এটি সঠিক উত্তর। গৃহীত উত্তরটি সিস্টেমের উপর একটি লুকানো নির্ভরতার সাথে দুর্বল নকশাকে উত্সাহ দেয়, অন্যদিকে এই উত্তরটি ইনজেকশন দেওয়ার মতো আরও একটি নির্ভরতা হিসাবে উপযুক্ত ডিজাইনের চিকিত্সার জন্য উত্সাহ দেয়।
অ্যান্ড্রু

30

এইরকম একটি পরিস্থিতিতে যেখানে আমাকে টেস্ট কেস লিখতে হয়েছিল যা পরিবেশ পরিবর্তনের উপর নির্ভরশীল , আমি নিম্নলিখিত চেষ্টা করেছিলাম:

  1. আমি স্টিফান বার্কনারের পরামর্শ অনুসারে সিস্টেম বিধিমালার জন্য গিয়েছিলাম । এটির ব্যবহার সহজ ছিল। তবে খুব শীঘ্রই, আমি আচরণটি নির্গত পেয়েছি। এক রান, এটি কাজ করে, খুব পরের দৌড়ে এটি ব্যর্থ হয়। আমি তদন্ত করে দেখেছি যে JUnit 4 বা উচ্চতর সংস্করণের সাথে সিস্টেম বিধিগুলি ভালভাবে কাজ করে। তবে আমার ক্ষেত্রে আমি কিছু জার ব্যবহার করছিলাম যা জুনেট 3 এর উপর নির্ভরশীল ছিল । সুতরাং আমি সিস্টেমের বিধিগুলি এড়িয়ে গেছি । এটিতে আপনি আরও এখানে দেখতে পাবেন @ JUnit- এ টেস্টসুইট ব্যবহার করার সময় নিয়ম টীকাটি কাজ করে না
  2. পরবর্তী আমি জাভা দ্বারা সরবরাহিত প্রসেস বিল্ডার শ্রেণীর মাধ্যমে পরিবেশ পরিবর্তনশীল তৈরি করার চেষ্টা করেছি । এখানে জাভা কোডের মাধ্যমে আমরা একটি পরিবেশের পরিবর্তনশীল তৈরি করতে পারি, তবে আপনাকে যে প্রক্রিয়া বা প্রোগ্রামের নামটি জানিনা তা আপনার জানা দরকার । এছাড়াও এটি শিশু প্রক্রিয়াটির জন্য পরিবেশের পরিবর্তনশীল তৈরি করে, মূল প্রক্রিয়ার জন্য নয়।

উপরোক্ত দুটি পদ্ধতির সাহায্যে আমি একটি দিন নষ্ট করেছি, তবে কোনও ফলসই হয়নি। তারপরে মাভেন আমার উদ্ধারে এসেছিলেন। আমরা মাভেন পিওএম ফাইলের মাধ্যমে পরিবেশ পরিবর্তনশীল বা সিস্টেমের বৈশিষ্ট্যগুলি সেট করতে পারি যা আমি মাভেন ভিত্তিক প্রকল্পের জন্য ইউনিট টেস্টিংয়ের পক্ষে সবচেয়ে ভাল উপায় মনে করি । নীচে আমি পিওএম ফাইলে প্রবেশ করেছিলাম is

    <build>
      <plugins>
       <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <configuration>
          <systemPropertyVariables>
              <PropertyName1>PropertyValue1</PropertyName1>                                                          
              <PropertyName2>PropertyValue2</PropertyName2>
          </systemPropertyVariables>
          <environmentVariables>
            <EnvironmentVariable1>EnvironmentVariableValue1</EnvironmentVariable1>
            <EnvironmentVariable2>EnvironmentVariableValue2</EnvironmentVariable2>
          </environmentVariables>
        </configuration>
      </plugin>
    </plugins>
  </build>

এই পরিবর্তনের পরে, আমি আবার টেস্ট কেসগুলি চালিয়েছিলাম এবং হঠাৎ সমস্ত প্রত্যাশার সাথে কাজ করে। পাঠকের তথ্যের জন্য, আমি মাভেন ৩.x এ এই পদ্ধতির অন্বেষণ করেছি , সুতরাং মাভেন ২.x সম্পর্কে আমার কোনও ধারণা নেই ।


2
এই সমাধানটি সেরা এবং গ্রহণযোগ্য হওয়া উচিত, কারণ আপনার কাছে লিবিবের মতো অতিরিক্ত কিছু লাগবে না won't ম্যাভেন একা যথেষ্ট যথেষ্ট কাজে লাগে। আপনাকে ধন্যবাদ @ আরআরডি
সেমো

@ সিমো এটির জন্য যদিও maven প্রয়োজন, যা একটি lib ব্যবহারের চেয়ে অনেক বড় প্রয়োজন। এটি জুনিট টেস্টকে পমের সাথে জুড়ে দেয় এবং সাধারণভাবে সরাসরি আইডিইতে চালানোর পরিবর্তে এখনই পরীক্ষাটি এমভিএন থেকে কার্যকর করা প্রয়োজন।
চিরলো

@ চিরলো, আপনি আপনার প্রোগ্রামটি কী টাই করতে চান তার উপর নির্ভর করে on মাভেন ব্যবহার করে, আপনি এক জায়গায় কনফিগার করতে পারেন এবং ঝরঝরে এবং সংক্ষিপ্ত কোড লিখতে পারেন। আপনি যদি গ্রন্থাগার ব্যবহার করেন তবে আপনাকে একাধিক জায়গায় কোড লিখতে হবে। আপনার JUnits চলমান পয়েন্ট সম্পর্কে, আপনি মাভেন ব্যবহার করলেও আপনি ELipse এর মত IDE থেকে JUnits চালাতে পারবেন।
আরএলডি

@ আরআরডি, একলাইপস সম্পর্কে আমার জানা একমাত্র উপায় এটি জুনিটের পরিবর্তে 'ম্যাভেন' রান কনফিগারেশন হিসাবে চালিত হবে যা অনেক বেশি জটিল এবং ঠিক সাধারণ জুনিট ভিউয়ের পরিবর্তে পাঠ্য আউটপুট রয়েছে। এবং আমি আপনার পরিষ্কার এবং সংক্ষিপ্ত কোড এবং একাধিক জায়গায় কোড লিখতে পয়েন্টটি পুরোপুরি অনুসরণ করি না। আমার জন্য, পরে জুনিট পরীক্ষায় ব্যবহৃত পমটিতে পরীক্ষার ডেটা রাখা তাদের একসাথে থাকার চেয়ে বেশি অস্পষ্ট। আমি সম্প্রতি এই পরিস্থিতিতে ছিলাম এবং ম্যাথিউফারওয়েলের পদ্ধতির অনুসরণ করে শেষ হয়েছি, গ্রন্থাগারগুলির / পম ট্রিকগুলির প্রয়োজন নেই এবং সমস্ত কিছুই একই পরীক্ষায় এক সাথে রয়েছে।
চিরলো

1
এটি পরিবেশের ভেরিয়েবলগুলিকে হার্ড-কোডেড করে তোলে এবং সেগুলি System.getenv এর একটি অনুরোধ থেকে পরবর্তীটিতে পরিবর্তন করা যাবে না। সঠিক?
ইয়ান স্টুয়ার্ট

12

আমি মনে করি এটির সবচেয়ে পরিষ্কার উপায় হ'ল মকিতো.স্পাই () with এটি উপহাস করা এবং চারপাশে যাওয়ার জন্য একটি পৃথক শ্রেণী তৈরি করার চেয়ে কিছুটা বেশি হালকা।

আপনার পরিবেশের পরিবর্তনশীল আনতে অন্য পদ্ধতিতে সরান:

@VisibleForTesting
String getEnvironmentVariable(String envVar) {
    return System.getenv(envVar);
}

এখন আপনার ইউনিট পরীক্ষায় এটি করুন:

@Test
public void test() {
    ClassToTest classToTest = new ClassToTest();
    ClassToTest classToTestSpy = Mockito.spy(classToTest);
    Mockito.when(classToTestSpy.getEnvironmentVariable("key")).thenReturn("value");
    // Now test the method that uses getEnvironmentVariable
    assertEquals("changedvalue", classToTestSpy.methodToTest());
}

12

আমার মনে হয় না এটি এখনও উল্লেখ করা হয়েছে, তবে আপনি পাওয়ারমোকিটোও ব্যবহার করতে পারেন :

প্রদত্ত:

package com.foo.service.impl;

public class FooServiceImpl {

    public void doSomeFooStuff() {
        System.getenv("FOO_VAR_1");
        System.getenv("FOO_VAR_2");
        System.getenv("FOO_VAR_3");

        // Do the other Foo stuff
    }
}

আপনি নিম্নলিখিত করতে পারেন:

package com.foo.service.impl;

import static org.mockito.Mockito.when;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
import static org.powermock.api.mockito.PowerMockito.verifyStatic;

import org.junit.Beforea;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.MockitoAnnotations;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest(FooServiceImpl.class)
public class FooServiceImpTest {

    @InjectMocks
    private FooServiceImpl service;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);

        mockStatic(System.class);  // Powermock can mock static and private methods

        when(System.getenv("FOO_VAR_1")).thenReturn("test-foo-var-1");
        when(System.getenv("FOO_VAR_2")).thenReturn("test-foo-var-2");
        when(System.getenv("FOO_VAR_3")).thenReturn("test-foo-var-3");
    }

    @Test
    public void testSomeFooStuff() {        
        // Test
        service.doSomeFooStuff();

        verifyStatic();
        System.getenv("FOO_VAR_1");
        verifyStatic();
        System.getenv("FOO_VAR_2");
        verifyStatic();
        System.getenv("FOO_VAR_3");
    }
}

8
when(System.getenv("FOO_VAR_1")).thenReturn("test-foo-var-1")org.mockito.exceptions.misusing.MissingMethodInvocationException: when() requires an argument which has to be 'a method call on a mock'.ত্রুটির কারণ
অ্যান্ড্রেমনিয়

10

এনভায়রনমেন্ট ভেরিয়েবল থেকে জাভা কোডটি ডিকুয়াল করুন এমন একটি আরও বিমূর্ত ভেরিয়েবল রিডার সরবরাহ করুন যা আপনি একটি এনভায়রনমেন্টাল ভেরিয়েবলের সাথে বুঝতে পেরেছেন আপনার কোডটি পড়ে পরীক্ষা করার জন্য।

তারপরে আপনার পরীক্ষায় আপনি ভেরিয়েবল পাঠকের একটি পৃথক বাস্তবায়ন দিতে পারেন যা আপনার পরীক্ষার মান প্রদান করে।

নির্ভরতা ইনজেকশন এটি সাহায্য করতে পারে।


9

এই উত্তরটি প্রশ্নের আমি কিভাবে জাভা থেকে এনভায়রনমেন্ট ভেরিয়েবল সেট করব? System.getenv () -র মান (পরিবর্তনযোগ্য) মানচিত্র পরিবর্তন করার একটি উপায় সরবরাহ করে। সুতরাং এটি ওএস এনভায়রনমেন্ট ভেরিয়েবলের মানটি আসলে বদলে দেয় না, এটি ইউনিট পরীক্ষার জন্য ব্যবহার করা যেতে পারে কারণ এটি সিস্টেম.জেটেনভ কী ফিরিয়ে দেবে তা পরিবর্তন করে না ।


4

আশা করি বিষয়টি সমাধান হয়ে গেছে। আমি কেবল আমার সমাধানটি বলার জন্য ভেবেছিলাম।

Map<String, String> env = System.getenv();
    new MockUp<System>() {
        @Mock           
        public String getenv(String name) 
        {
            if (name.equalsIgnoreCase( "OUR_OWN_VARIABLE" )) {
                return "true";
            }
            return env.get(name);
        }
    };

1
আপনি জেমকিত ব্যবহার করছেন তা উল্লেখ করতে ভুলে গেছেন। :) নির্বিশেষে, এই সমাধানটি জুনিয়ট 5
রায়ান জে ম্যাকডনফ 21

1

যদিও আমি মনে করি এই উত্তরটি ম্যাভেন প্রকল্পগুলির পক্ষে সেরা, এটি প্রতিবিম্বের মাধ্যমেও অর্জন করা যেতে পারে ( জাভা 8 তে পরীক্ষিত ):

public class TestClass {
    private static final Map<String, String> DEFAULTS = new HashMap<>(System.getenv());
    private static Map<String, String> envMap;

    @Test
    public void aTest() {
        assertEquals("6", System.getenv("NUMBER_OF_PROCESSORS"));
        System.getenv().put("NUMBER_OF_PROCESSORS", "155");
        assertEquals("155", System.getenv("NUMBER_OF_PROCESSORS"));
    }

    @Test
    public void anotherTest() {
        assertEquals("6", System.getenv("NUMBER_OF_PROCESSORS"));
        System.getenv().put("NUMBER_OF_PROCESSORS", "77");
        assertEquals("77", System.getenv("NUMBER_OF_PROCESSORS"));
    }

    /*
     * Restore default variables for each test
     */
    @BeforeEach
    public void initEnvMap() {
        envMap.clear();
        envMap.putAll(DEFAULTS);
    }

    @BeforeAll
    public static void accessFields() throws Exception {
        envMap = new HashMap<>();
        Class<?> clazz = Class.forName("java.lang.ProcessEnvironment");
        Field theCaseInsensitiveEnvironmentField = clazz.getDeclaredField("theCaseInsensitiveEnvironment");
        Field theUnmodifiableEnvironmentField = clazz.getDeclaredField("theUnmodifiableEnvironment");
        removeStaticFinalAndSetValue(theCaseInsensitiveEnvironmentField, envMap);
        removeStaticFinalAndSetValue(theUnmodifiableEnvironmentField, envMap);
    }

    private static void removeStaticFinalAndSetValue(Field field, Object value) throws Exception {
        field.setAccessible(true);
        Field modifiersField = Field.class.getDeclaredField("modifiers");
        modifiersField.setAccessible(true);
        modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
        field.set(null, value);
    }
}

এর জন্য ধন্যবাদ! জাভাটির আমার সংস্করণটিতে নিম্নলিখিতগুলির মতো theCaseInsensitiveEnvironmentএকটি ক্ষেত্র রয়েছে এবং এর পরিবর্তে মনে হচ্ছে না theEnvironment: `` `envMap = নতুন হাশম্যাপ <> (); ক্লাস <?> ক্লাজ = ক্লাস.ফরনাম ("java.lang.ProcessEn पर्यावरण"); ফিল্ড দ্য এনভায়রনফিল্ড = ক্লজ.সেটডেক্লেয়ার্ডফিল্ড ("দ্য এনভায়রনমেন্ট"); ফিল্ড দ্য ইউনোডেফাইয়েবল এনভায়রনমেন্টফিল্ড = ক্লজ.সেটডেক্লেয়ারডফিল্ড ("দ্য ইউনোডেফাইয়েবল এনভায়রনমেন্ট"); অপসারণ স্ট্যাটিকফিনালঅ্যান্ডসেটভ্যালু (দ্য এনভায়রনফিল্ড, এনভ্যাম্যাপ); অপসারণ স্ট্যাটিকফিনালঅ্যান্ডসেটভ্যালু (দ্য ইনমোডাইফাইএবল এনভায়রনমেন্টফিল্ড, এনভ্যাম্যাপ); `` `
ইনটਨੇেক্স

-2

ঠিক আছে আপনি আপনার এনভির বিভিন্ন মান ঘোষণা করতে সেটআপ () পদ্ধতিটি ব্যবহার করতে পারেন। ধ্রুবকগুলিতে পরিবর্তনশীল। তারপরে বিভিন্ন দৃশ্যের পরীক্ষার জন্য ব্যবহৃত পরীক্ষাগুলিতে এই ধ্রুবকগুলি ব্যবহার করুন।


-2

আপনি জাভা এনভায়রনমেন্ট ভেরিয়েবল সম্পর্কে তথ্য পুনরুদ্ধার করতে চান, আপনি পদ্ধতি কল করতে পারেন: System.getenv();। বৈশিষ্ট্য হিসাবে, এই পদ্ধতিটি মান হিসাবে মান হিসাবে ভেরিয়েবলের নাম এবং ভেরিয়েবল মান সমন্বিত একটি মানচিত্র ফেরত দেয়। এখানে একটি উদাহরণ:

    import java.util.Map;

public class EnvMap {
    public static void main (String[] args) {
        Map<String, String> env = System.getenv();
        for (String envName : env.keySet()) {
            System.out.format("%s=%s%n", envName, env.get(envName));
        }
    }
}

পদ্ধতিটি getEnv()একটি যুক্তিও নিতে পারে। এই ক্ষেত্রে :

String myvalue = System.getEnv("MY_VARIABLE");

পরীক্ষার জন্য, আমি এই জাতীয় কিছু করব:

public class Environment {
    public static String getVariable(String variable) {
       return  System.getenv(variable);
}

@Test
 public class EnvVariableTest {

     @Test testVariable1(){
         String value = Environment.getVariable("MY_VARIABLE1");
         doSometest(value); 
     }

    @Test testVariable2(){
       String value2 = Environment.getVariable("MY_VARIABLE2");
       doSometest(value); 
     }   
 }

1
মূল বিষয়টি জুনিট টেস্ট থেকে এনভ ভেরিয়েবলগুলি অ্যাক্সেস না করা
তন্ময় ভট্টাচার্জি

-2

আমি মানচিত্রটি পেতে System.getEnv () ব্যবহার করি এবং আমি ক্ষেত্র হিসাবে রাখি, তাই আমি এটি উপহাস করতে পারি:

public class AAA {

    Map<String, String> environmentVars; 

    public String readEnvironmentVar(String varName) {
        if (environmentVars==null) environmentVars = System.getenv();   
        return environmentVars.get(varName);
    }
}



public class AAATest {

         @Test
         public void test() {
              aaa.environmentVars = new HashMap<String,String>();
              aaa.environmentVars.put("NAME", "value");
              assertEquals("value",aaa.readEnvironmentVar("NAME"));
         }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.