3

我正在尝试从属性文件中读取 Spring Boot 中单元测试用例的值。我有两个config.properties文件,一个在src/main/resources

prop = some-value

和一个src/test/resources

prop = some-test-value

主要应用类:

package company.division.project;

import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.PropertySource;

@SpringBootApplication(scanBasePackages = "company.division.project")
@PropertySource(value = "classpath:config.properties")
public class Application extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        System.setProperty("DUMMY_PROPERTY", "dummy-value");

        return application.sources(Application.class);
    }

    public static void main(String[] args) throws Exception {
        // Do nothing with main
    }
}

要测试的服务类:

package company.division.project.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

@Component
public class Service {
    @Autowired
    Environment environment;

    public String getProperty() {
        return environment.getProperty("prop");
    }

}

服务测试类。我尝试了两种方法来检索src/test/resources/config.properties文件中的值;一个带有@Autowired Environment, 一个带有 @Value注释...都不起作用:

package company.division.project.service;

import static org.junit.Assert.assertEquals;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.test.context.TestPropertySource;

@RunWith(MockitoJUnitRunner.class)
@TestPropertySource("classpath:config.properties")
public class ServiceTest {
    @InjectMocks
    Service service;

    @Autowired
    Environment environment;

    @Value("${prop}")
    private String expectedProperty;

    @Test
    public void testGetPropertyWithValueAnnotation() {
        assertEquals(expectedProperty, service.getProperty());
    }

    @Test
    public void testGetPropertyWithEnvironment() {
        assertEquals(environment.getProperty("prop"), service.getProperty());
    }
}

我在 StackOverflow 上的某个地方读到,为了在 Spring 测试类中自动连接组件,我需要为测试创建一个完整的上下文,所以我尝试了这个(更改注释和测试运行器):

package company.division.project.service;

import static org.junit.Assert.assertEquals;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.env.Environment;
import org.springframework.test.context.junit4.SpringRunner;


@RunWith(SpringRunner.class)
@SpringBootTest
public class ServiceTest {
    @InjectMocks
    Service service;

    @Autowired
    Environment environment;

    @Value("${prop}")
    private String expectedProperty;

    @Test
    public void testGetPropertyWithValueAnnotation() {
        assertEquals(expectedProperty, service.getProperty());
    }

    @Test
    public void testGetPropertyWithEnvironment() {
        assertEquals(environment.getProperty("prop"), service.getProperty());
    }
}

上下文已创建,但两种方法NullPointerException再次以 s 结尾。

4

2 回答 2

2

您的测试的问题是您试图以MockitoJUnitRunner.class错误的方式使用 to。

如果您正在使用模拟服务,则@InjectMocks需要确保需要Service.getProperty()通过模拟服务调用来返回值。如果您正在使用,SpringRunner.class那么您不应该拥有@InjectMocks但应该拥有@Autowired该服务。以下测试工作。

@RunWith(SpringRunner.class)
@SpringBootTest
public class ServiceTest {
    @Autowired
    Service service;

    @Autowired
    Environment environment;

    @Value("${prop}")
    private String expectedProperty;

    @Test
    public void testGetPropertyWithValueAnnotation() {
        assertEquals(expectedProperty, service.getProperty());
    }

    @Test
    public void testGetPropertyWithEnvironment() {
        assertEquals(environment.getProperty("prop"), service.getProperty());
    }
}

于 2019-09-23T13:35:24.883 回答
1

感谢@shazin 的回答和我自己的一些研究,我已经能够解决这个问题。

@RunWith基本上,在中指定的测试运行程序类和 Mockito 模拟的注释之间需要兼容。我们要测试这个Service类:

服务等级

@Component
public class Service {
    @Autowired
    Environment environment;

    public String getProperty() {
        return environment.getProperty("prop");
    }
}

如果您正在使用@RunWith(MockitoJUnitRunner.class),则可以使用@InjectMocks@Mock注释,如下所示。无论是什么都@AutowiredService与模拟自动连接:

测试类MockitoJUnitRunner

@RunWith(MockitoJUnitRunner.class)
public class ServiceTest {
    @InjectMocks
    Service service;
        @Mock
        Environment mockEnvironment;

    @Before
    public void before() {
        Mockito.when(mockEnvironment.getProperty("prop")).thenReturn("some-test-value")
    }
}

但是您不能在测试类本身中自动连接任何东西。这需要一个 Spring 上下文(需要一个 Spring 上下文来管理自动连接到对象中的 bean)。这就是@RunWith(SpringRunner.class)图片的来源。您可以使用它来运行具有专用 Spring 上下文的测试用例(您会注意到测试用例日志显示为每个带有@RunWith(SpringRunner.class)注释的测试类启动了一个新的 Spring 应用程序)。您还需要提供带有@SpringBootTest注释的配置详细信息。

需要注意的是,一个测试类@RunWith(SpringRunner.class)不会理解@InjectMocksand@Mock注释;您必须使用@MockBean注释。这将通过用模拟替换 bean 来有效地修改 Spring 上下文;任何带有@Autowired注释的东西都会自动与模拟 bean 自动连接:

测试类SpringRunner

@RunWith(SpringRunner.class)
@SpringBootTest(classes=Application.class)
public class ServiceTest {
    @Autowired
    Service service;

    @MockBean
    Environment mockEnvironment;

    @Before
    public void before() {
        Mockito.when(mockEnvironment.getProperty("prop")).thenReturn("some-test-value")
    }
}

所以......使用除了更改注释的名称( ->和-> )@RunWith(SpringRunner.class)之外没有任何效果,对吧?错误的。使用为您提供了测试用例中自动装配组件的功能。因此,如果您想使用实际的(不是模拟的),您也可以这样做;只需从专用的 Spring 上下文自动连接它:@InjectMocks@Autowired@Mock@MockBeanSpringRunnerEnvironment

测试类SpringRunner@Autowired环境

@RunWith(SpringRunner.class)
@SpringBootTest(classes=Application.class)
public class ServiceTest {
    @Autowired
    Service service;

    @Autowired
    Environment environment;

    @Test
    public void testServiceGetProperty() {
        assertEquals(environment.getProperty("prop"), service.getProperty("prop");
    }

}

这解决了问题。

于 2019-09-26T08:29:49.873 回答