So I have been asked to read up on mocking and BDD for our development team and play around with mocks so as to improve a handful of our existing unit tests (as an experiment).
I have ultimately chosen to go with Mockito for a number of reasons (some outside the scope of my control), but namely because it supports both stubbing and mocking for instances when mocking would not be appropriate.
I have spent all day learning about Mockito, mocking (in general) and BDD. And now I am ready to dig in and start augmenting our unit tests.
So we have a class called WebAdaptor that has a run() method:
public class WebAdaptor {
private Subscriber subscriber;
public void run() {
subscriber = new Subscriber();
subscriber.init();
}
}
Please note: I do not have a way to modify this code (for reasons outside the scope of this question!). Thus I do not have the ability to add a setter method for Subscriber, and thus it can be thought of as an unreachable "blackbox" inside of my WebAdaptor.
I want to write a unit test which incorporates a Mockito mock, and uses that mock to verify that executing WebAdaptor::run() causes Subscriber::init() to be called.
So here's what I've got so far (inside WebAdaptorUnitTest):
#Test
public void runShouldInvokeSubscriberInit() {
// Given
Subscriber mockSubscriber = mock(Subscriber.class);
WebAdaptor adaptor = new WebAdaptor();
// When
adaptor.run();
// Then
verify(mockSubscriber).init();
}
When I run this test, the actual Subscriber::init() method gets executed (I can tell from the console output and seeing files being generated on my local system), not the mockSubscriber, which shouldn't do (or return) anything.
I have checked and re-checked: init is public, is neither static or final, and it returns void. According to the docs, Mockito should have no problem mocking this object.
So it got me thinking: do I need to explictly associate the mockSubscriber with the adaptor? If this is a case, then ordinarily, the following would normally fix it:
adaptor.setSubscriber(mockSubscriber);
But since I cannot add any such setter (please read my note above), I'm at a loss as to how I could force such an association. So, several very-closely-related questions:
Can anyone confirm that I've set the test up correctly (using the Mockito API)?
Is my suspicion about the missing setter correct? (Do I need to associate these objects via a setter?)
If my above suspicion is true, and I can't modify WebAdaptor, are there any circumventions at my dispose?
Thanks in advance!
You need to inject the mock into the class which you are testing. You do not need access to Subscriber. The way mockito and other mocking frameworks help is that you do not need access to objects which you are interacting with. You do however need a way to get mock objects into the class you are testing.
public class WebAdaptor {
public WebAdaptor(Subscriber subscriber) { /* Added a new constructor */
this.subscriber = subscriber;
}
private Subscriber subscriber;
public void run() {
subscriber.init();
}
}
Now you can verify your interactions on the mock, rather than on the real object.
#Test
public void runShouldInvokeSubscriberInit() {
// Given
Subscriber mockSubscriber = mock(Subscriber.class);
WebAdaptor adaptor = new WebAdaptor(mockSubscriber); // Use the new constructor
// When
adaptor.run();
// Then
verify(mockSubscriber).init();
}
If adding the Subscriber to the constructor is not the correct approach, you could also consider using a factory to allow WebAdaptor to instantiate new Subscriber objects from a factory which you control. You could then mock the factory to provider mock Subscribers.
If you don't want to change the production code and still be able to mock the functionality of the Subscriber class you should have a look at PowerMock. It works fine together with Mockito and allows you to mock the creation of new objects.
Subscriber mockSubscriber = mock(Subscriber.class);
whenNew(Subscriber.class).withNoArguments().thenReturn(mockSubscriber);
Further details are explained in the documentation for the PowerMock framework.
There is a way to inject your mock into the class under test without making any modifications to the code. This can be done using the Mockito WhiteBox. This is a very good feature that can be used to inject the dependencies of your Class Under Test from your tests. Following is a simple example on how it works,
#Mock
Subscriber mockSubscriber;
WebAdaptor cut = new WebAdaptor();
#Before
public void setup(){
//sets the internal state of the field in the class under test even if it is private
MockitoAnnotations.initMocks(this);
//Now the whitebox functionality injects the dependent object - mockSubscriber
//into the object which depends on it - cut
Whitebox.setInternalState(cut, "subscriber", mockSubscriber);
}
#Test
public void runShouldInvokeSubscriberInit() {
cut.run();
verify(mockSubscriber).init();
}
Hope this helps :-)
You could have used PowerMock to mock the constructor call without changing the original code:
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest(WebAdaptor.class)
public class WebAdaptorTest {
#Test
public void testRunCallsSubscriberInit() {
final Subscriber subscriber = mock(Subscriber.class);
whenNew(Subscriber.class).withNoArguments().thenReturn(subscriber);
new WebAdaptor().run();
verify(subscriber).init();
}
}
You cannot mock the Subscriber using Mockito in your current implementation.
The problem you have is that the Subscriber is constructed and then immediately accessed, Mockito has no ability to replace (or spy) the Subscriber instance after creation but before the init method is called.
public void run() {
subscriber = new Subscriber();
// Mockito would need to jump in here
subscriber.init();
}
David V's answer solves this by adding the Subscriber to the constructor. An alternative that retains the hidden Subscriber construction would be to instantiate the Subscriber in a WebAdapter no-arg constructor and then use reflection to replace that instance before calling the run method.
Your WebAdapter would look like this,
public class WebAdaptor {
private Subscriber subscriber;
public WebAdaptor() {
subscriber = new Subscriber();
}
public void run() {
subscriber.init();
}
}
And you could use ReflectionTestUtils from Springframework's test module to inject dependencies into that private field.
#Test
public void runShouldInvokeSubscriberInit() {
// Given
Subscriber mockSubscriber = mock(Subscriber.class);
WebAdaptor adaptor = new WebAdaptor();
ReflectionTestUtils.setField( adaptor "subscriber", mockSubscriber );
// When
adaptor.run(); // This will call mockSubscriber.init()
// Then
verify(mockSubscriber).init();
}
ReflectionTestUtils is really just a wrapper about Java's reflection, the same could be achieved manually (and much more verbosely) without the Spring dependency.
Mockito's WhiteBox (as Bala suggests) would work here in place of ReflectionTestUtils, it is contained within Mockito's internal package so I shy away from it, YMMV.
Related
I have used twilio to send sms to my users using Java 8 and Spring. So I want Unit test my code using JUnit5 and Mockito. But the issue is that I am unable to mock this code
Message.creator(to, from, smsRequest.getMessage()).create();
So I would require help in successfully mocking this code for properly Unit testing my function.
Any help is appreciated.
You need to introduce an interface or abstract class between the twilio concrete implementation of Message.creator and your code that is using it. By doing so you can use standard mocking frameworks like mockito to create the mocks for you. And in the production setup you will inject code that uses the real implementation. For this you can use standard IOC tools, or go with constructor injection.
Message.creator(to, from, smsRequest.getMessage()).create();
returns a MessageCreator class, which actually does the job of sending the message.
Let's say your class has a method named sendMessage which calls
Message.creator(...).create().
Then, create a class that extends the actual class and overrides the sendMessage. In this way, you can quickly put the mock of MessageCreator class.
...
import com.twilio.rest.api.v2010.account
...
#Test
void testMockCreateOfTwilio() {
//given
messageCreator = mock(MessageCreator.class);
MyClassUnderTest underTest = new MyClassUnderTest();
underTest.setMessageCreator(messageCreator);
//when
//For example You can throw an exception with your mock
when(messageCreator.create()).thenThrow(ApiException.class);
underTest.sendMessage(new SomerParams);
//then
....
}
class MyClassUnderTest extends MyActualClass {
MessageCreator messageCreator;
public Message sendMessage(SomeParams params) {
return this.messageCreator.create();
}
public void setMessageCreator(MessageCreator messageCreator) {
this.messageCreator = messageCreator;
}
}
Is it possible to instantiate a class with a complex constructor without mocking or calling its constructor? This would be useful because the unit test class shouldn't need to change every time a new dependency was added to the service.
Mocking the service solves the problem by creating a new implementation of the class, with empty method overrides, but this isn't an instance of the implementation. This is a problem because any time a method in the mocked service is called, Mockito has to be told to call the real method. Instead, an actual implementation of the service would be preferred.
For example:
class ComplexService {
private Service service1;
private Service service2;
private Service service3;
private Service service4;
private Service service5;
ComplexConstructor(Service service1, Service service2, Service service3, Service service4, Service service5) {
this.service1 = service1;
this.service2 = service2;
this.service3 = service3;
this.service4 = service4;
this.service5 = service5;
}
boolean methodToTest() {
return service1.get();
}
}
In the unit test class, is it possible to have an instantiation of a implementation without having to call its constructor?
public class ComplexConostructorTest {
private ComplexConstructor complexConstructor;
private Service serviceMock;
#Before
public void init() {
/*
Somehow create implementation of complexConstructor
without calling constructor
. . .
*/
// Mock dependency
ReflectionTestUtils.setField(complexConstructor,
"service1",
serviceMock = Mockito.mock(Service.class));
}
#Test
public void service1Test() {
when(serviceMock.get())
.thenReturn(true);
assertTrue(complexConstructor.methodToTest());
}
}
Edit
It is possible using reflection, I was hoping there was a built in way in JUnit or Mockito to achieve the same thing. Here is how to do it using reflection.
#Before
public void init() {
Constructor<?> constructor = ComplexConstructor.class.getConstructors()[0];
complexConstructor = (ComplexConstructor) constructor.newInstance(new Object[constructor.getParameterCount()]);
// Mock dependency
ReflectionTestUtils.setField(complexConstructor,
"service1",
serviceMock = Mockito.mock(Service.class));
}
This is not possible, as far as I know, but you can simply add a simpler Constructor to your class and use that for testing. On the other hand, if the test tests the object in a state that is different to what it will be in the app, I'm not sure how good such a test would be.
You can, but you probably don't want to:
ComplexConstructor partialMock =
Mockito.mock(ComplexConstructor.class, CALLS_REAL_METHODS);
This "partial mock" instance will not have its constructor or field initializers called, but all calls to the system under test will invoke the class's real behavior. (Technically the class will also have its equals and hashCode overridden for Mockito's purposes, and the class will be a generated subclass of ComplexConstructor instead of ComplexConstructor itself.)
In this way, you can be insulated from the constructor, but because you are suppressing an arbitrary subset of the class-under-test's behavior it is much more difficult to determine exactly what you're testing in order to be confident the system works because the test passes. That should be your main goal in testing, and it may be difficult to achieve that with partial mocks. Colleagues or collaborators may rightly observe that you shouldn't mock your system under test for exactly this reason.
Though personally I don't think it's wrong or unexpected for you to need to change your unit tests to supply mocks when needed, you could create a factory separate from your test that supplies testing instances of ComplexConstructor, or consider using a dependency injection framework that automatically supplies mocks to your system under test.
Looks like you are mixing up several terms and concepts. Let me help you understand them better.
This would be useful because the unit test class shouldn't need to change every time a new dependency was added to the service.
Your class has a number of dependencies, that are provided via the constructor. If you are writing unit test your aim is only to test this dependent class, all dependencies should be mocked. That's why it is called unit testing. This means that with every new dependency of your class the test should be updated by adding new mock and its mocked behaviour.
Mockito has to be told to call the real method. Instead, an actual implementation of the service would be preferred.
Consider integration tests, in this case, you can mock only some amount of dependencies while others will work as intended or "real" until you mock them of course. However, if you want just to avoid supporting tests then it is not the right approach.
Please don't try to hack your tested class from your test by reflection. This can lead to wrong test results, waste of time and overall disappointment :) Mocking libraries like PowerMock and JMockit provide any kind of hacks, like ones you've tried to implement yourself and are in general too powerful.
With Great Power Comes Great Responsibility
You can create helper methods as part of your test code, for example some factory methods with descriptive names that construct the object. For example, make_default_ComplexService and more the like, just as needed by your tests. The tests could then use these methods, and if the constructor changes, you will in many cases only have to update the helper methods and not all of the tests. This approach is generic enough to also separate your test from drastic changes like turning the "constructor with parameters" approach into the "non-argument constructor with lots of setters" approach.
This approach will reduce maintenance effort for your tests, you will still use the original constructor (because it is called by the factory) rather than some fake constructor, and your test code might even be more readable than with the direct constructor's calls if the factory methods' names are well chosen.
You could add a parameterless constructor to your class and create setter for all your fields.
class ComplexService {
private Service service1;
private Service service2;
private Service service3;
private Service service4;
private Service service5;
public ComplexService(){
super();
}
...
public void setService1(Service service1){
this.service1 = service1;
}
//for other fields too
...
}
In your test you call it like:
myService = new ComplexService()
myService.setService1(service1);
...
I have a class that implements a cache and I want to write a JUnit test for it.
The class implements and interface with methods like:
public void insert(Object key, Object value);
public Object getFromCache(Object key);
and the basic implementation is a singleton.
I am writing a JUnit test but I don't know how to properly create a dummy cache with data in order to use for testing.
Right now I am doing:
#Test
public void myTest() {
MyCache cache = MyCache.getInstance();
populateWithData(cache);
//test cache
asserEquals etc
}
How can I avoid using the getInstance() and not populate on each test?
Apparently I slightly misread your question.
As the other two answers state, if you want to have a specific cache which you can read from when running each testcase, you could use a ´#before´ method, which initializes your object to be used in your testcase. Each ´#before´ method defined is called prior to calling each testcase. This means that you can write the code to instantiate the object once instead of many times.
Note that if you want to do something different in a testcase, consider adding the customization at the top of that, instead of edition your #before method, since that will impact all your testcases.
Just for clarity's sake, I will include some code:
MyCache cache = null;
#before
public void initCache(){
cache = MyCache.getInstance();
populateWithData(cache);
}
// ... rest of your program here ...
Original answer:
You can use this if you want to do more fancy testing of more complicated objects. This can still be used in conjunction with the ´#before´ annotation
You could try mockito...
This is basically a framework to mock off a function or class, that you are not interested in implementing in its totally, especially for testing.
Here is a sample using a mocked off list:
import static org.mockito.Mockito.*;
// mock creation
List mockedList = mock(List.class);
// using mock object - it does not throw any "unexpected interaction" exception
mockedList.add("one");
mockedList.clear();
// selective, explicit, highly readable verification
verify(mockedList).add("one");
verify(mockedList).clear();
// you can mock concrete classes, not only interfaces
LinkedList mockedList = mock(LinkedList.class);
// stubbing appears before the actual execution
when(mockedList.get(0)).thenReturn("first");
// the following prints "first"
System.out.println(mockedList.get(0));
// the following prints "null" because get(999) was not stubbed
System.out.println(mockedList.get(999));
You can basically tell mockito which functions you expect to call on the object, and what you expect the result to be... very versatile. I expect that it will fulfill your needs.
'Reset' singleton before each test. More details can be found here.
For example:
#Before
public void resetMyCacheSingleton() throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
Field instance = MyCache.class.getDeclaredField("instance");
instance.setAccessible(true);
instance.set(null, null);
}
You can use #BeforeClass annotation to do something which will be common and may be computational expensive stuff.
This will ran only once before all the testcases.
#BeforeClass
public static void myTest() {
MyCache cache = MyCache.getInstance();
populateWithData(cache);
//test cache
asserEquals etc
}
P.S. Since #BeforeClass can be used with static method only, populateWithData() needs to be static as well. and since populateWithData() method is static, variables used inside it must be static as well.
You can also check #AfterClass to clean/reset some data/resources.
I have a unit test that fails because it indirectly calls a method which is dependent upon a service. But when unit tests are run, the service is offline. I tried using Mockito for mocking the behavior of this service dependent method, but the problem is that this method is a static method in a final class, so Mockito does not work in this case.
I also tried using PowerMock with Mockito, but again as the method is not called directly from the unit test, it does not work. This is the skeleton of my unit test:
#RunWith(PowerMockRunner.class)
#PrepareForTest(FinalClassWithStaticMethod.class)
public class MyObjTestCase {
#Test public void myRandomTest() throws Exception {
PowerMockito.mockStatic(FinalClassWithStaticMethod.class);
MyObj returnObj = new MyObj();
// setup fields for returnObj
...
...
PowerMockito.when(FinalClassWithStaticMethod.staticMethod((AnotherObj)anyObject())).thenReturn(returnObj);
AnotherObj obj = new AnotherObj();
// setup fields for obj...
MyObj mockedObj = FinalClassWithStaticMethod.staticMethod(obj); // This returns the mocked value.
// TestUtil.staticMethod calls another class' method which calls FinalClassWithStaticMethod.staticMethod.
MyObj myObj = TestUtil.staticMethod(obj); // This does not return mocked value.
}
}
My questions:
Are the unit tests even meant for such scenarios?
Is there a way by which I can get this unit test to work without modifying the final class? In case I do have to modify the existing classes, what is the correct way of doing it by minimal effects on the dependent code? Although it is a specific scenario, links to examples that exhibit such refactoring will be great help.
In your case, you should ideally be mocking the service object. The mocking will only work if the method that is calling the service is using the mocked object. If the client for the service can be created and passed to the class calling the service directly from the unit test (setter/constructor) when the object is created in the unit test, then you don't have to make too many changes.
Sample code:
class CallsService {
public CallsService(final ServiceClient client) {
... }
public someMethod() {
client.callService();
}
}
In unit test:
void test() {
ServiceClient mockedClient = mock(ServiceClient.class);
// Setup mocks to return as required
CallsService caller = new CallsService(mockedClient);
}
This way the caller will use the mockedClient in the unit test, and in the actual program it can get a client to the real service.
I am using mockito for mock the unit test cases and am getting the following exception
org.mockito.exceptions.misusing.NotAMockException:
Argument passed to verify() is of type ConsumerImpl and is not a mock!
Make sure you place the parenthesis correctly!
See the examples of correct verifications:
verify(mock).someMethod();
verify(mock, times(10)).someMethod();
verify(mock, atLeastOnce()).someMetenter code herehod();
and my code is
MessageConsumer mConsumer = Mockito.mock(MessageConsumer.class);
String data = "new Message for Testing";
Message message = new Message(data.getBytes());
Mockito.when(mConsumer.next(10, TimeUnit.SECONDS)).thenReturn(message);
StringParserTest parserTest = new StringParserTest();
ConsumerImpl<String> consumer = new ConsumerImpl<String>(mConsumer, parserTest);
String mes=Mockito.verify(consumer,VerificationModeFactory.times(3)).consumeMessage(10,TimeUnit.SECONDS);
Please some one help me to solve this problem
Thanks in Advance
SRN
Well, that's exactly what mockito says, you are not passing a mock to verify !
ConsumerImpl<String> consumer = new ConsumerImpl<String>(mConsumer, parserTest);
String mes=Mockito.verify(consumer,VerificationModeFactory.times(3)).consumeMessage(10,TimeUnit.SECONDS);
Plus if you verified a mock why would you want to store the result of the invocation you verify, it wouldn't make sense since the consumer is mocked. Verify is to verify calls on mocked objects that are the collaborators of your unit tested object. Which in your case is not really clear.
Also you never use your mock mConsumer instance.
You should definitely separate your test in 3 phase, one for the fixture, one for the action, and one for the verifications. Use the BDD terminology to achieve that, it augments understanding and readability for the tester and future reader of this code (And Mockito offers them in the API through BDDMockito).
As I don't really get what the code is trying to test from the code you gave, I'll be imagining things. So for example you'll write this kind of code (using import static) :
// given a consumer
MessageConsumer message_consumer = mock(MessageConsumer.class);
String the_message_data = "new Message for Testing";
given(message_consumer.next(10, SECONDS)).willReturn(new Message(the_message_data.getBytes()));
// when calling the client of the customer (which is the unit that is tested)
new MessageProcessor(message_consumer).processAll();
// then verify that consumeMessage is called 3 times
verify(message_consumer, times(3)).consumeMessage(10, SECONDS);
Remember Mockito helps you focus on interactions between objects — as it's the most important notion of object oriented programming — and especially between the tested one and his collaborators that will certainly be mocked.
Usually we mock using #InjectMock and we try to verify a method called from inside the test case method.
Here is one scenario which generally give issue.
public class A{
#Autowired
Service s
public void method1(){
method2();
}
public void method2(){
s.someMethod();
}
}
public class ATest{
#InjectMocks
A a;
public void testM1(){
a.method1();
Mockito.verify(a, Mockito.times(1)).method2();
}
}
This will always give "NoAMockException while Mockito.verify"
instead of that we should use following verification.
public class ATest{
#InjectMocks
A a;
#Mock
Service s
public void testM1(){
a.method1();
Mockito.verify(s, Mockito.times(1)).someMethod();
}
}
Or if we want to verify() method2()
then we have to #Mock class A instead of #InjectMock