Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should you use the "Verify" and "VerifyAll" methods provided by Moq in your Unit Tests?

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.

like image 938
Agreene Avatar asked Apr 07 '15 23:04

Agreene


People also ask

What does MOQ verify do?

Verifies that all verifiable expectations have been met.

What is setup in MOQ?

Setup method is used to set expectations on the mock object For example: mock. Setup(foo => foo. DoSomething("ping")). Returns(true);


3 Answers

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:

  • return value of method (simple, common)
  • change in system state (simple, rare)
  • call to external component (complex, rare)

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.

like image 96
k.m Avatar answered Nov 23 '22 18:11

k.m


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.

like image 36
guillaume31 Avatar answered Nov 23 '22 19:11

guillaume31


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).

like image 27
Sunny Milenov Avatar answered Nov 23 '22 20:11

Sunny Milenov