How to avoid duplicate code when using mocks in unittests - unit-testing

I am using dependency injection to supply mocks for code outside of my class under test. I find myself writing alot of the same code over and over as I need to mock out AuthProvider, ConfigurationManager, etc. which are used in the method I want to test. The method contains branches (if-then-else) and therefore I have multiple tests in place to test all execution paths of the method. I am instantiating each of the mocks several times (once in each test method) but am wondering if this is the wrong way around?
Also I am putting up expectations for the mocks and preset responses which evidently are mostly copy-paste as such calls as to AuthProvider.Authenticate() are called in every method
In each method I setup a mock repository and at the end of each method I verify the mock repository. Should I prehaps have some sort of factory for creating these mocks along with setting their expectations and return values and if so how?
For implementation of mocks I am using RhinoMocks.

"instantiating each of the mocks several times" is not a problem. Objects are free.
Just be sure you aren't defining the mock classes numerous times. Classes are expensive.
Also, you have a "setUp" method in a TestCase that allows you to create a fixture that is used by all tests. Yes, it's rebuilt for each test. No, that's not a problem unless it's painfully slow.

Assuming you're using NUnit, you can use instance variables for your Mocks and reset them in Setup/Teardown. If you see repeated patterns then do what you do with production code: refactor and extract helper methods that express what you're trying to achieve (if there's no commonality at all, then there's a problem with the design of the production code).
If there are significant divisions in setup, consider writing more than one test class for your production class.
Finally, think about whether your production class is just too busy and some of the behaviour ought to be extracted out to a helper object.
Listen to the Tests!

Here is my take..
I would not use mock in the case... I would use a factory method to return a fake implementation of the class and use dependency injection to use this implementation instead.. this way you would avoid duplication and can reuse this implementation again n again... again this factory implementation need to be refactored properly i.e., no duplication..
Mocks, I guess should be used when you are testing some dynamic behavior.. something like.. did a method in sub-system was called when I perform some action on SUT.. and later on call verify() to verify this behavior... there is also a good article on Martin Folwer bliki Mock Aren't Stubs

You might want to look at using the AAA style of test so that you have multiple tests with a common setup. Here's a decent example.

Record and Replay frameworks like EasyMock fail if you dont set an expectation on a mock call. But frameworks like Mockito simply record all calls and let you verify only the ones that matter. So you dont have to set expectation on all methods in all tests.
And coming back to your Problem of instantiating Mocks in each test method, there's a better way than using setUp() method. Mockito provides a #Mock annotation. So you declare your variables(as fields) like:
#Mock Repository repositoryMock
and just call initMocks() in setUp(). All mock objects declared are automatically available in your tests without explicitly creating Mocks.

Related

Unit Testing RxJava Flowable using spock

I have below snippet for fetching data from MongoDB using com.mongodb.reactivestreams.client.MongoClient and Flowable
The snippet goes like:
Flowable
.fromPublisher(
mongoClient
.getDatabase(mydb)
.getCollection(mycollection)
.find()
.limit()
)
.firstOrError()
.toMaybe()
.doOnError(error -> { /* somecode */ })
I tried mocking every step of this fluent expression, e.g.
MongoDatabase someDb = Mock(MongoDatabase)
mongoClient.getDatabase(mydb) >> somedb
but on doing this somehow the test keeps running.
What is the correct way to unit test this using Spock?
Fluent interfaces are a PITA to mock, my strategy is to put those calls into a separate class / method and mock that. And then to test the fluent part in an integration test.
In addition to Leonard's idea, you might also want to look into implementing a special ThisResponse implements IDefaultResponse which always returns the mock instance for every mock method call and using that like Mock(defaultResponse: ThisResponse.INSTANCE) for your fluent API class(es). This works nicely as long as the fluent API methods used in the test are supposed to return this or at least another object of the given type. Only where another type is returned, you need to stub something.
Check this answer for more details. As soon as you update your question with a little MCVE, you may also ask follow-up questions if you have any problems using that solution.
Update 2022-03-08: I re-wrote the linked answer after learning about the special behaviour of EmptyOrDummyResponse for methods returning the mocked type. I am also describing now the related Spock 2 syntactic sugar syntax there.

Behavior of doReturn-when and when-thenReturn with mocked vs spied object

When using a spied object as test subject, If we don't want to call nested methods inside the method we are testing, Which of these (doReturn-when or when-thenReturn) can be used to mock those nested methods?
Is there a way to avoid getting invoked the real methods inside the method we are going to test?
In fact doesn't matter if you use doReturn-when or when-thenReturn method for this specific case, because considering a #Spy you will always call the real method.
You can avoid entering other methods by mocking them, but if you are using just Mockito it will be a problem (it doesn't have this approach, but PowerMock does). Particularly I disagree with this approach, because we are being too intrusive in our tests and private flow is a part of the whole flow, but you can do something like this:
SomeService mock = spy(SomeService.class);
doReturn(1).when(mock, "getNumber", ArgumentMatchers.anyInt());
For more details, you can verify PowerMock's official documentation. Also, is nice to know some basic unit testing concepts (stubs, mocks and so on).

How to extend Unity container for automocking?

I want Unity to automatically inject mocks for dependencies of SUTs in unit tests.
I'd prefer some kind of IServiceProvider implementation to customize (if needed) mocks creation.
Is it possible?
P.S. We use TypeMock
Typemock implemented something similar to what you're looking for.
Fake.Dependencies creates a real SUT object, injecting faked parameters to its longest Ctor.
Passing some of the parameters manually is also possible, the rest are automatically faked.
UnderTest real = Isolate.Fake.Dependencies<SUT>([args])
You can also get a proxy to a fake dependency later in the test.
var fake = Isolate.GetFake<F>(real);
I'm sure that implementing your own solution is also possible.

Is it a good idea to make assertions in mock objects for unit tests?

I'm testing code that uses a third-party PBKDF2class to make a hash. I'm mocking this object in my tests. This class takes a number of iterations as an argument, which increases the time it takes to hash. Is it a good idea to add an assertion inside the mock class to check that the correct number of iterations is being passed in, or should I add a piece of data to the fake hash it returns, so that my actual unit test can check the iteration count?
Indeed, it is a good idea to add assertion in mocked classes, although that isn't what most people would call it. That is how mock objects should work, they should both return data that the class being tested needs and verify that the class being tested is calling the right function and sending the right information.
However, don't mock these classes manually yourself, that'll take forever for all of the cases you need. Use a unit test library with strong mocking abilities, like the x-unit library (which is available for many languages, php-unit, j-unit, etc). These libraries allow you to easily mock an object, set up expectations and return values without you having to make hundreds of different mocks manually.
If the expectations aren't met on the mocked classes, the test will fail letting you know something went wrong.

When should I mock?

I have a basic understanding of mock and fake objects, but I'm not sure I have a feeling about when/where to use mocking - especially as it would apply to this scenario here.
Mock objects are useful when you want to test interactions between a class under test and a particular interface.
For example, we want to test that method sendInvitations(MailServer mailServer) calls MailServer.createMessage() exactly once, and also calls MailServer.sendMessage(m) exactly once, and no other methods are called on the MailServer interface. This is when we can use mock objects.
With mock objects, instead of passing a real MailServerImpl, or a test TestMailServer, we can pass a mock implementation of the MailServer interface. Before we pass a mock MailServer, we "train" it, so that it knows what method calls to expect and what return values to return. At the end, the mock object asserts, that all expected methods were called as expected.
This sounds good in theory, but there are also some downsides.
Mock shortcomings
If you have a mock framework in place, you are tempted to use mock object every time you need to pass an interface to the class under the test. This way you end up testing interactions even when it is not necessary. Unfortunately, unwanted (accidental) testing of interactions is bad, because then you're testing that a particular requirement is implemented in a particular way, instead of that the implementation produced the required result.
Here's an example in pseudocode. Let's suppose we've created a MySorter class and we want to test it:
// the correct way of testing
testSort() {
testList = [1, 7, 3, 8, 2]
MySorter.sort(testList)
assert testList equals [1, 2, 3, 7, 8]
}
// incorrect, testing implementation
testSort() {
testList = [1, 7, 3, 8, 2]
MySorter.sort(testList)
assert that compare(1, 2) was called once
assert that compare(1, 3) was not called
assert that compare(2, 3) was called once
....
}
(In this example we assume that it's not a particular sorting algorithm, such as quick sort, that we want to test; in that case, the latter test would actually be valid.)
In such an extreme example it's obvious why the latter example is wrong. When we change the implementation of MySorter, the first test does a great job of making sure we still sort correctly, which is the whole point of tests - they allow us to change the code safely. On the other hand, the latter test always breaks and it is actively harmful; it hinders refactoring.
Mocks as stubs
Mock frameworks often allow also less strict usage, where we don't have to specify exactly how many times methods should be called and what parameters are expected; they allow creating mock objects that are used as stubs.
Let's suppose we have a method sendInvitations(PdfFormatter pdfFormatter, MailServer mailServer) that we want to test. The PdfFormatter object can be used to create the invitation. Here's the test:
testInvitations() {
// train as stub
pdfFormatter = create mock of PdfFormatter
let pdfFormatter.getCanvasWidth() returns 100
let pdfFormatter.getCanvasHeight() returns 300
let pdfFormatter.addText(x, y, text) returns true
let pdfFormatter.drawLine(line) does nothing
// train as mock
mailServer = create mock of MailServer
expect mailServer.sendMail() called exactly once
// do the test
sendInvitations(pdfFormatter, mailServer)
assert that all pdfFormatter expectations are met
assert that all mailServer expectations are met
}
In this example, we don't really care about the PdfFormatter object so we just train it to quietly accept any call and return some sensible canned return values for all methods that sendInvitation() happens to call at this point. How did we come up with exactly this list of methods to train? We simply ran the test and kept adding the methods until the test passed. Notice, that we trained the stub to respond to a method without having a clue why it needs to call it, we simply added everything that the test complained about. We are happy, the test passes.
But what happens later, when we change sendInvitations(), or some other class that sendInvitations() uses, to create more fancy pdfs? Our test suddenly fails because now more methods of PdfFormatter are called and we didn't train our stub to expect them. And usually it's not only one test that fails in situations like this, it's any test that happens to use, directly or indirectly, the sendInvitations() method. We have to fix all those tests by adding more trainings. Also notice, that we can't remove methods no longer needed, because we don't know which of them are not needed. Again, it hinders refactoring.
Also, the readability of test suffered terribly, there's lots of code there that we didn't write because of we wanted to, but because we had to; it's not us who want that code there. Tests that use mock objects look very complex and are often difficult to read. The tests should help the reader understand, how the class under the test should be used, thus they should be simple and straightforward. If they are not readable, nobody is going to maintain them; in fact, it's easier to delete them than to maintain them.
How to fix that? Easily:
Try using real classes instead of mocks whenever possible. Use the real PdfFormatterImpl. If it's not possible, change the real classes to make it possible. Not being able to use a class in tests usually points to some problems with the class. Fixing the problems is a win-win situation - you fixed the class and you have a simpler test. On the other hand, not fixing it and using mocks is a no-win situation - you didn't fix the real class and you have more complex, less readable tests that hinder further refactorings.
Try creating a simple test implementation of the interface instead of mocking it in each test, and use this test class in all your tests. Create TestPdfFormatter that does nothing. That way you can change it once for all tests and your tests are not cluttered with lengthy setups where you train your stubs.
All in all, mock objects have their use, but when not used carefully, they often encourage bad practices, testing implementation details, hinder refactoring and produce difficult to read and difficult to maintain tests.
For some more details on shortcomings of mocks see also Mock Objects: Shortcomings and Use Cases.
A unit test should test a single codepath through a single method. When the execution of a method passes outside of that method, into another object, and back again, you have a dependency.
When you test that code path with the actual dependency, you are not unit testing; you are integration testing. While that's good and necessary, it isn't unit testing.
If your dependency is buggy, your test may be affected in such a way to return a false positive. For instance, you may pass the dependency an unexpected null, and the dependency may not throw on null as it is documented to do. Your test does not encounter a null argument exception as it should have, and the test passes.
Also, you may find its hard, if not impossible, to reliably get the dependent object to return exactly what you want during a test. That also includes throwing expected exceptions within tests.
A mock replaces that dependency. You set expectations on calls to the dependent object, set the exact return values it should give you to perform the test you want, and/or what exceptions to throw so that you can test your exception handling code. In this way you can test the unit in question easily.
TL;DR: Mock every dependency your unit test touches.
Rule of thumb:
If the function you are testing needs a complicated object as a parameter, and it would be a pain to simply instantiate this object (if, for example it tries to establish a TCP connection), use a mock.
You should mock an object when you have a dependency in a unit of code you are trying to test that needs to be "just so".
For example, when you are trying to test some logic in your unit of code but you need to get something from another object and what is returned from this dependency might affect what you are trying to test - mock that object.
A great podcast on the topic can be found here