junit 如何在通过构造函数接收参数的类中使用@SpyBean?

qv7cva1a  于 2022-11-11  发布在  其他
关注(0)|答案(1)|浏览(148)

我正在为一个Sping Boot 应用程序创建一些单元测试。
在名为ComicService的类中,有一个名为getComicByApi的方法,我想为该方法创建一个测试,但此方法访问同一类的另一个名为getHash的方法。
我需要配置getHash的行为,因此我在创建ComicService对象时使用了**@SpyBean注解。
问题是,当运行测试时,它在我使用Mockito.when().thenReturn()配置getHash行为的部分给出了错误。
我发现这个错误与我使用
@BeforeEach public void setUp()**来示例化带注解的类有关,其中@SpyBean传递了它的构造函数参数,但我仍然不知道如何解决这个问题。
有人知道如何解决这个问题吗?

漫画服务

@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);
    }

}

漫画服务测试

@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.
3zwtqj6y

3zwtqj6y1#

看起来@SpyBean无法找到您的服务类的示例。快速的替代方法是从ComicService comicService;中删除@SpyBean,并在@BeforeEach中执行以下操作:

@BeforeEach
    public void setUp() {
        this.comicService = Mockito.spy(new ComicService("ae78641e8976ffdf3fd4b71254a3b9bf", "eb9fd0d8r8745cd0d554fb2c0e7896dab3bb745", marvelClient));

    }

在这里,您创建了spy,然后在测试类中使用它。

相关问题