Java 在使用Mockito测试我的SpringBoot应用程序时,如何从属性文件传递变量?

Java 在使用Mockito测试我的SpringBoot应用程序时,如何从属性文件传递变量?,java,spring-boot,unit-testing,mockito,integration-testing,Java,Spring Boot,Unit Testing,Mockito,Integration Testing,解决方案 我没有用@Value(${path.to.randomizer})在DiceRollerService类中注释字段“path”,而是将注释传递给类构造函数: @Service public class DiceRollerService { private String path; private final CustomHttpClient client; @Autowired public DiceRollerService(CustomHttpClient client, @V

解决方案

我没有用@Value(${path.to.randomizer})在DiceRollerService类中注释字段“path”,而是将注释传递给类构造函数:

@Service
public class DiceRollerService {
private String path;
private final CustomHttpClient client;

@Autowired
public DiceRollerService(CustomHttpClient client, @Value("${path.to.randomizer}") String path) {
    this.client = client;
    this.path = path;
}
在这种情况下,如果使用默认构造函数,则路径字段将链接到应用程序属性中的相应值,否则,如果使用此特定构造函数,则可以通过它传递特定路径值。下面是我的单元测试现在的样子:

@RunWith(MockitoJUnitRunner.class)
public class DiceRollerTest {
private static final String PATH_FOR_TEST = "Some URL path";
private static final int DICE_NUMBER_ONE = 2;
private static final int DICE_NUMBER_TWO = 2;

@Mock
private CustomHttpClient client;

private DiceRollerService diceRollerService;

@Before
public void init() {
    diceRollerService = new DiceRollerService(client, PATH_FOR_TEST);
}

@Test
public void testDiceRollerServiceWithCorrectPathAndBody() {
    Dices expected = new Dices(DICE_NUMBER_ONE, DICE_NUMBER_TWO);
 when(client.getResponseBodyFromClient(PATH_FOR_TEST)).thenReturn(BODY_TEST);
    Dices actual = diceRollerService.roll();
    Assert.assertEquals(expected, actual);
    verify(client).getResponseBodyFromClient(anyString());
}
初始问题

在我的小项目的单元和/或集成测试方面,我需要一些帮助。我有一个类,它只有一个返回骰子模型的重要方法:

@Service
public class DiceRollerService {
    @Value("${path.to.randomizer}")
    private String path;
    private final static int FIRST_DICE_NUMBER_POS = 0;
    private final static int SECOND_DICE_NUMBER_POS = 2;
    private final CustomHttpClient client;

public DiceRollerService(CustomHttpClient client) {
    this.client = client;
}

public Dices roll() {
    String results = client.sendGetRequest(path).body();
    int firstNumber = Integer.parseInt(String.valueOf(results.charAt(FIRST_DICE_NUMBER_POS)));
    int secondNumber = Integer.parseInt(String.valueOf(results.charAt(SECOND_DICE_NUMBER_POS)));
    return new Dices(firstNumber, secondNumber);
}

public void setPath(String path) {
    this.path = path;
}
}
如您所见,在roll()方法中,我调用client.sendGetRequest(path)来获取HttpResponse的主体,并从中获取一些数据,以便构建和返回骰子模型。除了实际路径位于我的属性文件src/main/resources/application.properties之外,没有什么复杂的地方。 后来,我决定为我的项目添加一些测试来检查逻辑:

public class DiceRollerTest {
@Mock
private CustomHttpClient client;

@InjectMocks
private DiceRollerService diceRollerService;

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

@Test
public void test() {
    Dices expected = new Dices(2, 2);
    when(client.sendGetRequest(anyString()).body()).thenReturn("2 2 ");
    Dices actual = diceRollerService.roll();
    Assert.assertEquals(expected, actual);
    verify(client, times(1)).sendGetRequest(anyString()).body();
}
}
不幸的是,结果a在这一行得到了一个空指针:when(client.sendGetRequest(anyString()).body()).thenReturn(“2”); 看来我的模拟并不像我想象的那样有效。以下是我的所有依赖项:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-jsr310</artifactId>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-core</artifactId>
        <version>3.3.3</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-inline</artifactId>
        <version>3.3.3</version>
        <scope>test</scope>
    </dependency>
</dependencies>

org.springframework.boot
SpringBootStarterWeb
org.springframework.boot
弹簧起动试验
测试
org.junit.vintage
朱尼特老式发动机
com.fasterxml.jackson.datatype
jackson-datatype-jsr310
朱尼特
朱尼特
4.13
测试
org.mockito
莫基托磁芯
3.3.3
测试
org.mockito
莫基托内联
3.3.3
测试

有什么方法可以在单元测试中使用我的属性吗?我怎样才能正确地解决这个问题?我将非常感谢你的任何建议。提前感谢。

面对这个确切的问题,我们开发了一个测试扩展,通过与
@InjectMocks
集成,非常优雅地解决了这个确切的问题:

这条线

 when(client.sendGetRequest(anyString()).body()).thenReturn("2 2 ");
被锁得太远了一步。您需要先存根
client.sendGetRequest(anyString())
的响应,然后才能存根
.body()
调用。差不多

 when(client.sendGetRequest(anyString()).thenReturn(myMockedHttpResponse); 
 when(myMockedHttpResponse.body()).thenReturn("2 2 ");

注入特性是另一个问题;考虑将一个属性文件放在/SRC/Test/Realthor下,或者查看<代码> @ TestPrimyTyrase< /代码>,或者将属性重构为<代码> @配置属性< /C> >类并注入其中之一或…无限可能:-)

@RunWith(MockitoJUnitRunner.class)您在class@HasnainAliBohra那不行,我以前有过这个注释,不过无论如何,谢谢你!谢谢你的建议!我决定稍微简化客户端逻辑,让它返回主体而不仅仅是响应。然后我模仿它:when(client.getResponseBodyFromClient(anyString())。然后return(“2”);又得了NPE。似乎问题在于使用属性文件中的路径。好吧,需要有人查看
@Value
注释并为字段赋值。如果您以
@SpringBootTest
的方式运行测试,那么Spring将处理它。如果不是,那么你必须用其他方法来解决它。如果你想在十分钟内完成它,那么创建一个setter(具有包可见性,可能用
@VisibleForTesting
注释)并从测试中设置它。是的,我已经读到,如果要添加@springbootest注释,应该可以解决问题,我做了,但对我来说也不起作用。我尝试添加此注释,并且在测试包下创建了一个具有相同属性的资源包。在我看来,要么我做错了什么,要么我知道的不多,不应该解决问题
 when(client.sendGetRequest(anyString()).body()).thenReturn("2 2 ");
 when(client.sendGetRequest(anyString()).thenReturn(myMockedHttpResponse); 
 when(myMockedHttpResponse.body()).thenReturn("2 2 ");