如何在接收构造函数参数的类中使用@spybean?
我正在为Spring Boot应用程序创建一些单元测试。
在称为 comicservice 的类中,有一种称为 getcomicbyapi 的方法,我想为该方法创建一个测试,但是此方法访问了同一类的另一种方法,称为 Gethash 。
我需要配置Gethash的行为,因此我使用 @spybean 注释来创建 comicservice 对象。
问题在于,在运行测试时,它在我使用mockito.when()。thenreturn()的部分中会出现一个错误来配置Gethash的行为。
我发现该错误与我使用 @beforeach public void setup()使用@spybean通过其构造函数论证实例化的班级有关,但我仍然不知道如何解决,它。
有人知道如何解决这个问题吗?
ComicService
@Service
public class ComicService {
private String publicKey;
private String privateKey;
private MarvelClient marvelClient;
public ComicService(@Value("${marvel.public_key}")String publicKey,
@Value("${marvel.private_key}") String privateKey, MarvelClient marvelClient) {
this.publicKey = publicKey;
this.privateKey = privateKey;
this.marvelClient = marvelClient;
}
public MarvelAPIModelDTO getComicByApi(Integer idComicMarvel) {
String timeStamp = String.valueOf((int)(System.currentTimeMillis() / 1000));
String hash = getHash(timeStamp);
MarvelAPIModelDTO comic = marvelClient.getComic(idComicMarvel, timeStamp, timeStamp, hash);
return comic;
}
public String getHash(String timeStemp) {
String value = timeStemp+privateKey+publicKey;
MessageDigest md;
try {
md = MessageDigest.getInstance("MD5");
} catch(NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
BigInteger hash = new BigInteger(1, md.digest(value.getBytes()));
return hash.toString(16);
}
}
comicserviceTest
@ExtendWith(SpringExtension.class)
@ActiveProfiles("test")
public class ComicServiceTest {
@SpyBean
ComicService comicService;
@MockBean
MarvelClient marvelClient;
@BeforeEach
public void setUp() {
this.comicService = new ComicService("ae78641e8976ffdf3fd4b71254a3b9bf", "eb9fd0d8r8745cd0d554fb2c0e7896dab3bb745", marvelClient);
}
@Test
public void getComicByApiTest() {
// Scenario
MarvelAPIModelDTO foundMarvelAPIModelDTO = createMarvelAPIModelDTO();
//It's giving an error on this line
Mockito.when(comicService.getHash(Mockito.anyString())).thenReturn("c6fc42667498ea8081a22f4570b42d03");
Mockito.when(marvelClient.getComic(Mockito.anyInt(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString())).thenReturn(foundMarvelAPIModelDTO);
// Execution
MarvelAPIModelDTO marvelAPIModelDTO = comicService.getComicByApi(1);
// Verification
Assertions.assertThat(marvelAPIModelDTO.getData().getResults().get(0).getId()).isEqualTo(1);
}
}
错误
at com.gustavo.comicreviewapi.services.ComicServiceTest.getComicByApiTest(ComicServiceTest.java:58)
You cannot use argument matchers outside of verification or stubbing.
Examples of correct usage of argument matchers:
when(mock.get(anyInt())).thenReturn(null);
doThrow(new RuntimeException()).when(mock).someVoidMethod(any());
verify(mock).someMethod(contains("foo"))
This message may appear after an NullPointerException if the last matcher is returning an object
like any() but the stubbed method signature expect a primitive argument, in this case,
use primitive alternatives.
when(mock.get(any())); // bad use, will raise NPE
when(mock.get(anyInt())); // correct usage use
Also, this error might show up because you use argument matchers with methods that cannot be mocked.
Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode().
Mocking methods declared on non-public parent classes is not supported.
I'm creating some unit tests for a Spring Boot application.
In a class called ComicService there is a method called getComicByApi and I want to create a test for that method, but this method accesses another method of the same class called getHash.
I need to configure the behavior of getHash, so I used the @SpyBean annotation in creating the ComicService object.
The problem is that when running the test it gives an error in the part where I use Mockito.when().thenReturn() to configure the behavior of getHash.
I found that the error is related to the fact that I use @BeforeEach public void setUp() to instantiate the annotated class with @SpyBean passing its constructor arguments, but I still don't know how to solve it.
Does anyone know how to solve this problem?
ComicService
@Service
public class ComicService {
private String publicKey;
private String privateKey;
private MarvelClient marvelClient;
public ComicService(@Value("${marvel.public_key}")String publicKey,
@Value("${marvel.private_key}") String privateKey, MarvelClient marvelClient) {
this.publicKey = publicKey;
this.privateKey = privateKey;
this.marvelClient = marvelClient;
}
public MarvelAPIModelDTO getComicByApi(Integer idComicMarvel) {
String timeStamp = String.valueOf((int)(System.currentTimeMillis() / 1000));
String hash = getHash(timeStamp);
MarvelAPIModelDTO comic = marvelClient.getComic(idComicMarvel, timeStamp, timeStamp, hash);
return comic;
}
public String getHash(String timeStemp) {
String value = timeStemp+privateKey+publicKey;
MessageDigest md;
try {
md = MessageDigest.getInstance("MD5");
} catch(NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
BigInteger hash = new BigInteger(1, md.digest(value.getBytes()));
return hash.toString(16);
}
}
ComicServiceTest
@ExtendWith(SpringExtension.class)
@ActiveProfiles("test")
public class ComicServiceTest {
@SpyBean
ComicService comicService;
@MockBean
MarvelClient marvelClient;
@BeforeEach
public void setUp() {
this.comicService = new ComicService("ae78641e8976ffdf3fd4b71254a3b9bf", "eb9fd0d8r8745cd0d554fb2c0e7896dab3bb745", marvelClient);
}
@Test
public void getComicByApiTest() {
// Scenario
MarvelAPIModelDTO foundMarvelAPIModelDTO = createMarvelAPIModelDTO();
//It's giving an error on this line
Mockito.when(comicService.getHash(Mockito.anyString())).thenReturn("c6fc42667498ea8081a22f4570b42d03");
Mockito.when(marvelClient.getComic(Mockito.anyInt(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString())).thenReturn(foundMarvelAPIModelDTO);
// Execution
MarvelAPIModelDTO marvelAPIModelDTO = comicService.getComicByApi(1);
// Verification
Assertions.assertThat(marvelAPIModelDTO.getData().getResults().get(0).getId()).isEqualTo(1);
}
}
Error
at com.gustavo.comicreviewapi.services.ComicServiceTest.getComicByApiTest(ComicServiceTest.java:58)
You cannot use argument matchers outside of verification or stubbing.
Examples of correct usage of argument matchers:
when(mock.get(anyInt())).thenReturn(null);
doThrow(new RuntimeException()).when(mock).someVoidMethod(any());
verify(mock).someMethod(contains("foo"))
This message may appear after an NullPointerException if the last matcher is returning an object
like any() but the stubbed method signature expect a primitive argument, in this case,
use primitive alternatives.
when(mock.get(any())); // bad use, will raise NPE
when(mock.get(anyInt())); // correct usage use
Also, this error might show up because you use argument matchers with methods that cannot be mocked.
Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode().
Mocking methods declared on non-public parent classes is not supported.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
看起来
@spybean
无法找到您服务类的实例。快速替代方案是从comicservice comicservice;
&在您的@beforeeach
中进行关注:在这里,您正在创建间谍&然后在测试课内使用它。
It looks like
@SpyBean
is unable to find instance of your service class. Quick alternative for this is just remove@SpyBean
fromComicService comicService;
& do following in your@BeforeEach
:Here, you are creating spy & then using it inside your test class.
您可以使用, @oildbean注释@spybean,可以使用mockito.when()。thencalleRealMethod(),您需要调用真实方法和mockito.when()。 。这样,在这种情况下,必须摆脱您的所有问题,您可以按照自己的意愿进行嘲笑。
例如:
在测试课中,您必须在下面声明班级的模拟豆子,并根据需要嘲笑它们。相反,您可以使用thenAnswer(),thenthrows(),(),而不是donothing()用于void方法,可以使用doanswer(),dothrow(),dothrow(),doreturn(),
如果您的类无需bean,则可以声明bean如下:
这些方法仍然保持不变:
当(clazz.Method())。然后()和void donothing()。当(clazz).method()。
You can use ,@MockBean annotation instead @SpyBean and can use Mockito.when().thenCallRealMethod() as you need to call real method and Mockito.when().thenReturn() at the same time if you want to mock some method. This way have to rid you of all your problems in that case and you can mock as you wanted.
For example :
In test class you have to declare a mock bean of your class as below and to mock them as you want. Instead thenReturn() you can use thenAnswer(), thenThrows(), then(), and instead doNothing() for void methods you can use doAnswer(), doThrow(), doReturn():
If your class not Bean you can declar it as below :
The methods still stay the same :
when(clazz.method()).then() and for void doNothing().when(clazz).method().