It seems like using them as a method to ascertain whether the method under test executed properly is counterproductive because it will lead to brittle tests. In other words you're tying the test to the implementation. So if you later want to change the implementation you're also going to have to change the test. I'm asking this question because I was trained to always use at least one of these methods in every unit test and I think I may have just had an epiphany that this is actually a very bad practice.
Verifies that all verifiable expectations have been met.
Setup method is used to set expectations on the mock object For example: mock. Setup(foo => foo. DoSomething("ping")). Returns(true);
First of all, it is important to understand that Verify
-family methods are there for a reason -- they allow you to test unobservable1 behavior of your system. What do I mean by that? Consider simple example of application generating and sending reports. Your final component will most likely look like this:
public void SendReport(DateTime reportDate, ReportType reportType)
{
var report = generator.GenerateReport(reportDate, reportType);
var reportAsPlainText = converter.ConvertReportToText(report);
reportSender.SendEmailToSubscribers(body: reportAsPlainText);
}
How do you test this method? It doesn't return anything, thus you cannot check values. It doesn't change state of the system (like, flipping some flag), thus you cannot check that either. The only visible result of SendReport
being called is the fact that report was sent via SendEmailToSubscribers
invocation. This is the main responsibility of SendReport
method -- and this is what unit tests should verify.
Of course, your unit tests should not and will not check whether some email was sent or delivered. You will verify mock of reportSender
. And this is where you use Verify
methods. To check that some call to some mock actually took place.
As a final note, Roy Osherove in his book Art Of Unit Testing (2nd edition) separates unit tests into three categories, depending on what can be checked:
Last category is where you use mocks and Verify
methods on them. For other two, stubs are enough (Setup
methods).
When your code is designed correctly, such test will (last category) be in minority in your code base, somewhere in 5% - 10% range (number taken from Roy's book, in line with my observations).
1: Unobservable as in that caller cannot easily verify what exactly happend after the call.
Mock-based testing
There's a lot of debate around the brittleness of mocks in unit tests and whether they are a good thing or not. I personally think it's a tradeoff you have to make between maintainability and robustness. The more you put your production code under unit test pressure, testing it in isolation with mocks, the less possible implementations will pass the tests. You can thus force your production code into robustness and good design. On the other hand, it does tie yourself to a particular implementation and increases the maintenance burden because more tests will have to be changed as soon as an implementation detail changes.
The VerifyAll() syntax
It's mostly a matter of taste, but I find that VerifyAll()
is not intention revealing, i.e. when you read a test suite you would expect to get a good idea of the specifications just by looking at the assertions, and VerifyAll()
carries no meaning at all. Even when I write mock-based tests I prefer the Arrange Act Assert approach with specific assert failure messages. It's clearer and less "magical" than a catch-all VerifyAll()
call.
Using VerifyAll() in each and every test method
It's at best overkill and at worst will cause damage to your test suite.
As a general rule, a unit test should test only one thing. Systematically calling VerifyAll()
in addition to your normal assertion brings confusion -- if the test fails you can't know for sure what went wrong.
As far as readability, you're just adding noise to each of your tests. It's very difficult just by reading a test method to trace back to what that VerifyAll()
really means.
You generally want to choose where you apply design pressure on your implementations with mocks and not apply it blindly everywhere, because there's a maintenance price to it.
So if you really have to use VerifyAll()
, better to write separate tests for it IMO.
The preferred way is to use AAA. But for external dependencies with void return type (lets say void WriteData(Data data)), Verify can be useful (or Setup, and then VerifyAll).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With