【问题标题】:Having trouble mocking System.getenv calls in junit在junit中模拟System.getenv调用时遇到问题
【发布时间】:2021-08-25 02:00:41
【问题描述】:

我正在尝试使用 junit 和 mockito(对此非常新)为 Spring Boot 应用程序编写单元测试。基本上在我的代码中,我在 manifest.yml 文件(用于部署)中为特定 URL 指定了一个环境变量,我可以在我的代码中通过 String URL = System.getenv("VARIABLE") 访问它。但是,我的单元测试遇到了很多麻烦,因为 URL 变量显然是未定义的。我尝试了here 的解决方案,但意识到这只是为了模拟环境变量,如果你是从实际测试本身调用它,而不是你依赖于可以从代码访问的环境变量。

有什么方法可以设置,以便在运行测试时,我可以设置可以在代码中访问的环境变量?

【问题讨论】:

    标签: java unit-testing junit


    【解决方案1】:

    您可以使用PowerMockito 模拟静态方法。此代码演示了模拟 System 类和存根 getenv()

    @RunWith(PowerMockRunner.class)
    @PrepareForTest({System.class})
    public class Xxx {
    
        @Test
        public void testThis() throws Exception {
            System.setProperty("test-prop", "test-value");
            PowerMockito.mockStatic(System.class);
    
            PowerMockito.when(System.getenv(Mockito.eq("name"))).thenReturn("bart");
            // you will need to do this (thenCallRealMethod()) for all the other methods
            PowerMockito.when(System.getProperty(Mockito.any())).thenCallRealMethod();
    
            Assert.assertEquals("bart", System.getenv("name"));
            Assert.assertEquals("test-value", System.getProperty("test-prop"));
        }
    }
    

    我相信这说明了您要完成的工作。 可能有一种更优雅的方法可以使用 PowerMockito.spy() 来执行此操作,我只是不记得了。

    您需要为 System.class 中由您的代码直接或间接调用的所有其他方法执行 thenCallRealMethod()

    【讨论】:

    • 嘿,我不需要测试本身的环境变量,我只需要它,这样当测试本身运行带有环境变量的代码时,它将被定义为我设置的任何内容它。 B/c 现在是的,它是在测试中定义的,但是当测试执行它正在测试的实际代码时,它是未定义的。
    • 明白了,我添加的代码只是演示了 System.getenv("name") 返回预期值的事实。当您的非单元测试代码调用 System.getenv() 时,您将看到类似的结果(即模拟 System 将继续在您的非单元测试代码中工作)。因此,在您的单元测试中,使用如下行:PowerMockito.when(System.getenv(Mockito.eq("name"))).thenReturn("bart"); 来设置您的环境。然后,您的非单元测试代码应该会看到这些值
    • 如果这不起作用,请发回问题,我可能会帮助您。
    • 嘿,它正在工作,但它在我的单元测试中导致另一个错误。我收到以下错误 java.lang.ExceptionInInitializerError: null at java.lang.Integer.parseInt(Integer.java:454) 这会干扰其他系统调用吗?
    • 是的,我们已经mock了System,我们需要做的是“spy”System(也称为部分mock)。给我一分钟,我会帮你写代码。
    【解决方案2】:

    这可以通过https://github.com/webcompere/system-stubs实现

    你有几个选择:

    EnvironmentVariables environmentVariables = new EnvironmentVariables("VARIABLE", "http://testurl");
    
    // then put the test code inside an execute method
    environmentVariables.execute(() -> {
       // inside here, the VARIABLE will contain the test value
    });
    
    // out here, the system variables are back to normal
    

    或者可以使用 JUnit4 或 5 插件来完成:

    @ExtendWith(SystemStubsExtension.class)
    class SomeTest {
    
        @SystemStub
        private EnvironmentVariables environment = new EnvironmentVariables("VARIABLE", "http://testurl");
    
        @Test
        void someTest() {
            // inside the test the variable is set
            // we can also change environment variables:
    
            environment.set("OTHER", "value");
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-10
      • 2023-02-13
      • 1970-01-01
      • 2022-08-16
      • 1970-01-01
      • 2019-05-12
      相关资源
      最近更新 更多