Showing posts with label Mockito. Show all posts
Showing posts with label Mockito. Show all posts
Monday, April 10, 2017
Mocking static method calls
Very simple example on how we can use method delegation to enable unit testing where there is a dependency to an static method call.
Labels:
dependencies,
hard wired dependency,
java,
Mock,
Mockito,
static method call,
TDD,
Unit Testing
Thursday, June 9, 2016
Mockito ArgumentCaptor example
Lets observe the following class
If we were to test the method doSomething() what we would be interested in,
perhaps mostly is to make sure that the collaborator that it uses is reached and the appropriate
parameters are passed. We could do that very easily by just verifying on a mock
But there is a peculiar thing about this method. The argument that is passed into the collaborator
function doStuffWith() its using an object. Objects as its well known, contain other objects and/or
primitive variables. Since the object thing its being created internally in the method rather than be
injected(Its a hardwired dependency), we have no way of accurately knowing about it anything else but its type. So if we were curious about knowing more precisely about that object, what we would have to do is to spy on it. Mockito, allows us to spy on the objects that are passed to the mocks using a little tool called Argument Captor.
Let's have a look at how this test would look like if we were spying the object thing.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public class MyService { private Collaborator collaborator; public MyService(Collaborator collaborator) { this.collaborator = collaborator; } public void doSomething() { Thing thing = new Thing(); thing.setType("ABC"); collaborator.doStuffWith(thing); } } |
If we were to test the method doSomething() what we would be interested in,
perhaps mostly is to make sure that the collaborator that it uses is reached and the appropriate
parameters are passed. We could do that very easily by just verifying on a mock
1 2 3 4 5 6 7 8 9 10 11 12 | public class MyServiceTest { private Collaborator collaborator = Mockito.mock(Collaborator.class); private MyService myService = new MyService(collaborator); @Test public void shouldDoSomething() throws Exception { myService.doSomething(); verify(collaborator).doStuffWith(any(Thing.class)); } } |
But there is a peculiar thing about this method. The argument that is passed into the collaborator
function doStuffWith() its using an object. Objects as its well known, contain other objects and/or
primitive variables. Since the object thing its being created internally in the method rather than be
injected(Its a hardwired dependency), we have no way of accurately knowing about it anything else but its type. So if we were curious about knowing more precisely about that object, what we would have to do is to spy on it. Mockito, allows us to spy on the objects that are passed to the mocks using a little tool called Argument Captor.
Let's have a look at how this test would look like if we were spying the object thing.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public class MyServiceTest { private Collaborator collaborator = mock(Collaborator.class); private MyService myService = new MyService(collaborator); @Test public void shouldUseTheRightThing() throws Exception { ArgumentCaptor<Thing> argument = ArgumentCaptor.forClass(Thing.class); myService.doSomething(); verify(collaborator).doStuffWith(argument.capture()); assertThat(argument.getValue().getType(),is("ABC")); } } |
As you see, spying is an interesting way of in a non intrusive manner(without having to refactor), you can discover things about your code.
Now a question comes to our head. But declaring that object of type Thing in the method like that, is not an smell? Well, maybe but have in mind that if you were to inject that object from either the constructor or via a setter injection, we could say that you would be changing the api of the class. So that is not very good, because maybe you don't know if the clients that use the class are actually capable of providing the object thing or if would that even make sense form a design point of view.
To express this last point in a more pragmatical form, I am going to show you another 2 more intrusive refactoring to this class that could help you test that object, but that will need from you to sacrifice in design.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public class MyService { private Collaborator collaborator; private ThingBuilder thingBuilder; public MyService(Collaborator collaborator, ThingBuilder builder) { this.collaborator = collaborator; this.thingBuilder = builder; } public void doSomething() { Thing thing = thingBuilder.withType("ABC").build(); collaborator.doStuffWith(thing); } } |
If you had a builder, you could mock it and train it, but you would pay a design price of having to add the builder to the constructor.
Even if you choose to use a setter to set the builder or keeping the original constructor as it is(so you don't affect the clients) and overloading, you are still sacrificing your design for the purpose of the test. Your test would also become more complex. It would look like this:
1 2 3 4 5 6 7 8 9 10 11 | @Test public void shouldUseTheRightThing() throws Exception { Thing thing = new Thing(); thing.setType("ABC"); when(thingBuilder.withType(anyString())).thenReturn(thingBuilder); when(thingBuilder.build()).thenReturn(thing); myService.doSomething(); verify(collaborator).doStuffWith(thing); } |
The other alternative I was thinking about would be to override equals and hashcode, so you could do a comparison in your test against a newly created object that would be the
expectation.
1 2 3 4 5 6 7 8 9 | @Test public void shouldUseTheRightThing() throws Exception { Thing thing = new Thing(); thing.setType("ABC"); myService.doSomething(); verify(collaborator).doStuffWith(thing); } |
It looks naive, but again is intrusive. You are adding 2 methods in your entity, just for the purpose of making the test green.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | public class Thing { private String type; public String getType() { return type; } public void setType(String type) { this.type = type; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Thing thing = (Thing) o; return type != null ? type.equals(thing.type) : thing.type == null; } @Override public int hashCode() { return type != null ? type.hashCode() : 0; } } |
Labels:
ArgumentCaptor,
Best Practice,
java,
Mockito,
testing,
tips and tricks
Monday, February 24, 2014
paranoia testing
Somebody told me once a funny story about a woman who day after day kept arriving late to work, because once on her way to the office, she kept having the need to go back home again and again just to check that she unplugged the iron from the wall socket. Her unfounded fear was such that one day she finally decided to take the iron with her to the office in her handbag.
A common unfounded fear that some developers sometimes have when working with the database, is that they will fail to query it for whatever reason and they feel the need of testing that the database is returning them the expected values. It is common to see horrible tests like this one:
The above test has many problems, not just it is slow, also it is wrongly aimed because is not testing the functionality of the application, it just testing that some third party framework(hibernate in this case) is working properly.
Developers who do this, don't understand that the database is just a detail/add-on of the application.
It is fine to perform a smoke test to ping the database if they want(just to verify that the configuration of the ORM framework was correctly done), but testing that the HQL or the hibernate criteria are returning some values is wrong.
"Hibernate, MySQL, Oracle... all are just vendors, their solutions will work, you don't need to test them again!"
Focus on testing the functionality by mocking the dependencies you have with the database.
The only thing that counts at the end of the day is that the inputs and outputs to the service layer are processed correctly. If the data comes from a database, a file, a socket... doesn't matter at all.
Here an alternative test that will mock a dependency to the database and will check that the data is processed correctly:
Now tests main concern is the functionality and not how the data is added to, or retrieved from the database.
I trained the mock to behave as expected and I verified that its behavoir was executed as expected.
The database was not at all a concern.
A common unfounded fear that some developers sometimes have when working with the database, is that they will fail to query it for whatever reason and they feel the need of testing that the database is returning them the expected values. It is common to see horrible tests like this one:
@Test
public void whenAddingANewUserTheUserIsSavedToTheDatabase() {
//Tell hibernate to add this user to the database
ormAdapter.add(userFactory("djordje", "123"));
//Find the user and check its values
User savedValueInDatabase = adapter.find("djordje");
assertThat(savedValueInDatabase.getName(),is("djordje"));
assertThat(savedValueInDatabase.getPassword(),is("123"));
//Delete the test data
ormAdapter.delete(savedValueInDatabase.getName());
}
The above test has many problems, not just it is slow, also it is wrongly aimed because is not testing the functionality of the application, it just testing that some third party framework(hibernate in this case) is working properly.
Developers who do this, don't understand that the database is just a detail/add-on of the application.
It is fine to perform a smoke test to ping the database if they want(just to verify that the configuration of the ORM framework was correctly done), but testing that the HQL or the hibernate criteria are returning some values is wrong.
"Hibernate, MySQL, Oracle... all are just vendors, their solutions will work, you don't need to test them again!"
Focus on testing the functionality by mocking the dependencies you have with the database.
The only thing that counts at the end of the day is that the inputs and outputs to the service layer are processed correctly. If the data comes from a database, a file, a socket... doesn't matter at all.
Here an alternative test that will mock a dependency to the database and will check that the data is processed correctly:
@Test
public void loginTest() {
PersonManagementAdapterORM adapterORM = mock(PersonManagementAdapterORM.class);
when(adapterORM.find("djordje","123")).thenReturn(new Person("djordje","123"));
LoginService service = new LoginServiceImpl(adapterORM);
boolean authorized = service.login("djordje","123");
verify(adapterORM).find("djordje","123");
assertThat(authorized,is(true));
}
Now tests main concern is the functionality and not how the data is added to, or retrieved from the database.
I trained the mock to behave as expected and I verified that its behavoir was executed as expected.
The database was not at all a concern.
Labels:
Best Practice,
database,
framework,
hibernate,
java,
Mockito,
testing,
Unit Testing
Thursday, May 23, 2013
How to verify that void methods were called using Mockito
You can also read this article in our brand new medium space. Click here! Remember follow Javing on medium to make sure you don't miss out on some of the great new upcoming content.
Mockito is one of the most popular mocking frameworks for java.
This post Is just little miscellaneous where I will show you how to mock and verify a void method call.
Sometimes when we test a call to a void method all we want to do is just make sure that at some point in its life cycle, another method will be called with certain parameters.
Let's see the following example:
In the above piece of legacy code the most important part is a method called "someMethod()". We must make sure that it is called in a proper way, but unfortunately it belongs to a dependency to which we have no access and also to make it more complicated it is inside a private method.
Mockito framework could help us mock and verify that method call.
Here is how we can do it:
The most important things to highlight in this test class are:
Mockito is one of the most popular mocking frameworks for java.
This post Is just little miscellaneous where I will show you how to mock and verify a void method call.
Sometimes when we test a call to a void method all we want to do is just make sure that at some point in its life cycle, another method will be called with certain parameters.
Let's see the following example:
public class SomeClass {
private OtherClass otherClass;
public SomeClass(OtherClass otherClass) {
this.otherClass = otherClass;
}
protected void firstMethod(int value) {
if(value > 0) {
secondMethod("Yes!");
}
else {
secondMethod("No!");
}
}
private void secondMethod(String value) {
otherClass.someMethod(value);
}
}
In the above piece of legacy code the most important part is a method called "someMethod()". We must make sure that it is called in a proper way, but unfortunately it belongs to a dependency to which we have no access and also to make it more complicated it is inside a private method.
Mockito framework could help us mock and verify that method call.
Here is how we can do it:
package demo;
import static org.mockito.Mockito.verify;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import code.OtherClass;
import code.SomeClass;
public class TestClass {
@Mock
private OtherClass otherClass;
//Class under test
private SomeClass someClass;
@Before
public void prepareDependencies() {
MockitoAnnotations.initMocks(this);
someClass = new SomeClass(otherClass);
}
@Test
public void is_the_value_greater_than_zero() {
someClass.firstMethod(8);
verify(otherClass).someMethod("Yes!");
}
@Test
public void is_the_value_smaller_than_zero() {
someClass.firstMethod(-1);
verify(otherClass).someMethod("No!");
}
}
The most important things to highlight in this test class are:
- The class under test is never mocked.
- The dependencies of the class under test need to be mocked.
- By calling a method on a mock object we will mock that method call
- By using the verify() method we will test that at some point the method from the mock was called with the exact same parameters.
- The test class can access the protected method because the package name is the same.(But of course in your project structure test will be under src/test/java and production code under src/main/java)
Labels:
Hamcrest,
java,
Junit,
legacy,
miscellaneous,
Mock,
Mockito,
Unit Testing
Subscribe to:
Posts (Atom)