如何使用Mockito测试没有交互

huangapple go评论82阅读模式
英文:

How to test for no interaction using Mockito

问题

我目前正在学习Tomasz Kaczanowski写的书:“JUnit和Mockito实践单元测试”。现在,我正在阅读关于模拟、存根、测试替身和Mockito框架的部分。

作为练习的一部分,有一个待进行单元测试的程序,它向已订阅的客户端发送消息。以下是我目前遇到困难的部分。


  • 如果一个未订阅的客户端尝试取消订阅,应该发生什么情况?对此做出决定,编写一个验证此行为的测试,并相应地使RaceResultsService行为符合要求。

在这种情况下,我希望什么都不会发生。没有异常,没有消息...而且我想进行测试。但我该如何做呢?如何测试什么都不发生(而不深入实现,例如检查包含已订阅客户端的集合的大小)?

以下是我编写的测试,它并不如此:

@Test
void unsubscribingWhenAlreadyUnsubscribedShouldReturnVoid() {
    raceResults.removeSubscriber(clientA);

    verifyNoInteractions(clientA);
}

以下是RaceResultsService.java中相关的方法:

public class RaceResultsService {

    private Collection<Client> clients = new HashSet<Client>();

    // 其他字段和方法

    public void removeSubscriber(Client client) {
        clients.remove(client);
    }
}

显然,removeSubscriber方法实际上会执行某些操作,而不是什么都不做。它将执行HashSet.remove,但由于客户端不在clients集合(字段)中,它将不会修改任何内容。但如何在不实际触及相关的Collection<Client>的情况下进行测试呢?

我将不胜感激地接受任何建议,谢谢!

英文:

I'm currently studying the book written by Tomasz Kaczanowski: "Practical Unit Testing with JUnit and Mockito". Right now, I'm on the section concerning mocks, stubs, test doubles and the Mockito framework.

As part of the practice, there's a to-be-unit-tested program which sends messages to the subscribed clients. Here's the part of the exercise I'm currently struggling with.


  • What should happen if a client that is not subscribed tries to unsubscribe? Make up your mind about it, write a test which verifies this behaviour, and make RaceResultsService behave accordingly.

I would like nothing to happen on such occasion. No exception, no messages... And I want to test it. But how do I do that? How do I test that nothing happens (without getting too deep into implementation and, for example, checking the size of collection containing subscribed clients)?

Here's the test I've written which does not do so:

@Test
void unsubscribingWhenAlreadyUnsubscribedShouldReturnVoid() {
	raceResults.removeSubscriber(clientA);

	verifyNoInteractions(clientA);
}

And here's the concerned method of the RaceResultsService.java:

public class RaceResultsService {

	private Collection&lt;Client&gt; clients = new HashSet&lt;Client&gt;();

    // other fields and methods

    public void removeSubscriber(Client client) {
	    clients.remove(client);
    }
}

Obviously, the removeSubscriber method will actually do something, not nothing. It will execute the HashSet.remove but, as the client is not in the clients collection (field), it will not modify anything. But how do I test for this without actually touching the associated Collection&lt;Client&gt;?

I'd appreciate any suggestions, thanks!

答案1

得分: 1

以下是翻译好的部分:

  • "It would be hard to test that nothing happens. But you shouldn't: a unit test should only test observable behaviour. Whatever happens inside the implementation is not the test's concern."

    "很难测试什么都不发生。但你不应该这样做:单元测试应该只测试可观察到的行为。发生在实现内部的事情不是测试的关注点。"

  • "For example, if the implementation is changed to write a warning to a log file to inform the developers that a client might be buggy, this should probably not break the test. (You could argue that logging is also observable behaviour, but it's not usually part of the contract.)"

    "例如,如果实现被更改为向日志文件写入警告,以通知开发人员客户端可能存在问题,这可能不会破坏测试。(你可以说日志记录也是可观察的行为,但通常不是契约的一部分。)"

  • "So, what should you test for in this case?"

    "那么,在这种情况下,你应该测试什么呢?"

  • "Your test is already testing something, namely, that raceResults.removeSubscriber(clientA); does not throw an exception. In other words, it verifies that it's not an error to remove a client that's not subscribed. This might already be enough!"

    "你的测试已经在测试某些东西,也就是raceResults.removeSubscriber(clientA);不会抛出异常。换句话说,它验证了移除未订阅的客户端不会导致错误。这可能已经足够了!"

  • "If you also have a method like boolean isSubscribed(Client client), you could additionally verify that the client is not subscribed after unsubscribing."

    "如果你还有一个像boolean isSubscribed(Client client)这样的方法,你还可以验证在取消订阅后客户端是否未订阅。"

  • "You could also send a message and verify that the unsubscribed client does not receive it."

    "你还可以发送一条消息并验证取消订阅的客户端是否收不到它。"

英文:

It would be hard to test that nothing happens. But you shouldn't: a unit test should only test observable behaviour. Whatever happens inside the implementation is not the test's concern.

For example, if the implementation is changed to write a warning to a log file to inform the developers that a client might be buggy, this should probably not break the test. (You could argue that logging is also observable behaviour, but it's not usually part of the contract.)

So, what should you test for in this case?

Your test is already testing something, namely, that raceResults.removeSubscriber(clientA); does not throw an exception. In other words, it verifies that it's not an error to remove a client that's not subscribed. This might already be enough!

If you also have a method like boolean isSubscribed(Client client), you could additionally verify that the client is not subscribed after unsubscribing.

You could also send a message and verify that the unsubscribed client does not receive it.

huangapple
  • 本文由 发表于 2023年8月10日 16:35:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/76873971.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定