Java 在使用Mockito测试我的SpringBoot应用程序时,如何从属性文件传递变量?
解决方案 我没有用@Value(${path.to.randomizer})在DiceRollerService类中注释字段“path”,而是将注释传递给类构造函数: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
@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 ");