Mock只在Spring Environment中选择了属性

时间:2017-01-21 03:19:16

标签: spring unit-testing spring-boot junit mockito

我希望能够使用测试属性文件并仅覆盖一些属性。必须覆盖每一个属性都会变得很难看。

这是我用来测试模拟属性和在测试用例中使用现有属性的能力的代码

@RunWith(SpringRunner.class)
@SpringBootTest(classes = MyApp.class)
@TestPropertySource(
      locations = { "classpath:myapp-test.properties" },
      properties = { "test.key = testValue" })
public class EnvironmentMockedPropertiesTest {

   @Autowired private Environment env;
   // @MockBean private Environment env;

   @Test public void testExistingProperty() {
      // some.property=someValue
      final String keyActual = "some.property";
      final String expected = "someValue";
      final String actual = env.getProperty(keyActual);
      assertEquals(expected, actual);
   }

   @Test public void testMockedProperty() {
      final String keyMocked = "mocked.test.key";
      final String expected = "mockedTestValue";
      when(env.getProperty(keyMocked)).thenReturn(expected);
      final String actual = env.getProperty(keyMocked);
      assertEquals(expected, actual);
   }

   @Test public void testOverriddenProperty() {
      final String expected = "testValue";
      final String actual = env.getProperty("test.key");
      assertEquals(expected, actual);
   }

}

我发现的是:

  • @Autowired private Environment env;
    • testExistingProperty()testOverriddenProperty()传递
    • testMockedProperty()失败
  • @MockBean private Environment env;
    • testMockedProperty()传递
    • testExistingProperty()testOverriddenProperty()失败

有没有办法实现我的目标?

依赖关系:

<spring.boot.version>1.4.3.RELEASE</spring.boot.version>
...
<!-- Spring -->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot</artifactId>
   <version>${spring.boot.version}</version>
</dependency>
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-autoconfigure</artifactId>
   <version>${spring.boot.version}</version>
</dependency>
<!-- Starter for testing Spring Boot applications with libraries including JUnit,
   Hamcrest and Mockito -->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-test</artifactId>
   <version>${spring.boot.version}</version>
</dependency>

1 个答案:

答案 0 :(得分:1)

好的,我完成了这项工作,你需要使用Mockito来完成你想要的东西:

Maven依赖

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>2.6.4</version>
</dependency>

测试类设置

import static org.mockito.Mockito.*;
import static org.springframework.test.util.AopTestUtils.getTargetObject;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = MyApp.class)
@TestPropertySource(
      locations = { "classpath:myapp-test.properties" },
      properties = { "test.key = testValue" })

public class AnswerTest {

    // This will be only for injecting, we will not be using this object in tests.
    @Autowired
    private Environment env;

    // This is the reference that will be used in tests.
    private Environment envSpied;

    // Map of properties that you intend to mock
    private Map<String, String> mockedProperties;

    @PostConstruct
    public void postConstruct(){
        mockedProperties = new HashMap<String, String>();
        mockedProperties.put("mocked.test.key_1", "mocked.test.value_1");
        mockedProperties.put("mocked.test.key_2", "mocked.test.value_2");
        mockedProperties.put("mocked.test.key_3", "mocked.test.value_3");

        // We use the Spy feature of mockito which enabled partial mocking
        envSpied = Mockito.spy((Environment) getTargetObject(env));

        // We mock certain retrieval of certain properties
        // based on the logic contained in the implementation of Answer class
        doAnswer(new CustomAnswer()).when(envSpied).getProperty(Mockito.anyString());
    }

测试用例

    // Testing for both mocked and real properties in same test method
    @Test public void shouldReturnAdequateProperty() {
        String mockedValue = envSpied.getProperty("mocked.test.key_3");
        String realValue = envSpied.getProperty("test.key");

        assertEquals(mockedValue, "mocked.test.value_3");
        assertEquals(realValue, "testValue");
    }

实施Mockito的答案界面

    // Here we define what should mockito do:
    // a) return mocked property if the key is a mock
    // b) invoke real method on Environment otherwise
    private class CustomAnswer implements Answer<String>{

        @Override
        public String answer(InvocationOnMock invocationOnMock) throws Throwable {
            Object[] arguments = invocationOnMock.getArguments();
            String parameterKey = (String) arguments[0];

            String mockedValue = mockedProperties.get(parameterKey);

            if(mockedValue != null){
                return mockedValue;
            }

            return (String) invocationOnMock.callRealMethod();
        }
    }
}

尝试一下,如果一切都清楚,请告诉我。