I am learning TDD and I have some doubts when usings Mocks with mockito and junit.
Without mocks:
Contacto contacto = new Contacto("Santiago", "3022653192", "santi-1524#hotmail.com");
agenda.agregarContacto(contacto);
Assert.assertEquals(1, agenda.getSizeOfAgenda());
agenda.agregarContacto(contacto);
With mocks:
Mockito.verify(agenda).agregarContacto(contacto);
Mockito.when(agenda.getSizeOfAgenda()).thenReturn(1);
Assert.assertEquals(1, agenda.getSizeOfAgenda());
if I do the test without the mocks it takes less time than doing the test with Test for example: 2ms vs 356ms.
what are the benefits of doing the test with Mockito in this case?
Kind of missing the point of mocking. You use mocks to ensure ( mock ) the behavior of the surrounding services / external dependencies and everything that do not have to do directly with what you want to test.
In your example if you test your agenda service you will mock the contact as its irrelevant what contents it has as long as a contact goes in the agenda. If you also had lets say a calendar in the agenda you would mock that calendar also.
what are the benefits of doing the test with Mockito in this case?
In your case mocking was used in the wrong way.
A clear example of why you want to mock is a Service that will save something to your database.
public class SomeService {
private SomeRepository repo;
public SomeService(SomeRepository repo){
this.repo = repo;
}
public YourClass save(YourClass clazz){
repo.save(clazz);
}
}
public class SomeRepository {
private Connection yourDatabaseConnection;
public YourClass save(YourClass clazz){
yourDatabaseConnection.save(clazz);
}
}
So lets not bother how the connection is setup. When you will run a test from SomeService this will call your repo thus saving something in your database. Meaning you will have to setup a database and take care of the data inside which may create problems if you run multiple tests or tests in parallel ( if you and one of your colleges run the same test with you at the same time ). All this is a fuss and goes outside the unit-testing theory. Your unit is the Service in this scenario the SomeService. So you only need to test this.
#Test
public void test(){
final SomeRepository repo = mock(SomeRepository.class);
final SomeService serv = new SomeService(repo);
final YourClass clazz = mock(YourClass.class);
when(repo.save(clazz)).thenReturn(clazz);
YourClass response = serv.save(clazz);
Assert.assertEquals(clazz,response);
verify(repo).save(clazz);
}
This way you validate your service returns your object without any mutations in the middle as this was the expected behavior from the setup above. You validate it called the repository but you never actually calling it. This way no data will be added in your database ( meaning you dont need a database ) and the test is isolated and can be run in parallel a million times and it always have the same result.
Related
I am fairly new to mockito framework. I've been reading upon multiple tutorials in regards to it. One of them I was following is this: https://www.tutorialspoint.com/mockito/mockito_first_application.htm
There is a statement creating a mock of Stock Service.
In this example, we've created a mock of Stock Service to get the dummy price of some stocks
My question is Stock Service is a real service class or mock service class you have to manually stand up for mimicking the real service class. I am a bit confused. Having basic understanding of junit framework. What I had practiced before was if there is a service class Foo then I used actual class that provides all the exposed methods.
public class Foo {
public Foo() { } // construtor
public String returnAddress(String userId) {
// ...
return dataAccesobj.getAddress(userId);
}
}
Calling foo.returnAddress(..) in unit test if I remember right.
The reason I am asking this question is while I was working with mockitoto create a test method for a class, I ran into a unique(?) challenge.
I started with a real service class which depends on its super class constructor to return its instance. The challenge I ran into was this super class constructor initiates DB connection and loading/parsing properties files which I do not need for my test. I was thinking about how to prevent DB connection and loading/reading prop files....
I thought I read from one of mockito tutorials you can isolate testing without having such services. I tried with #Mock and #Spy (not fully understanding well still what they are for..) but it didn't make a difference for output (maybe I misused those annotations).
So what I did was actually creating fake/mock class out of real service class (e.g. Foo) by simply copying it and renamed it as FooMock and put it in src/test/java folder in where unit test class is running from. I kept the mock class exactly same as the real service class except taking out unwanted logic such as db connection or loading/reading prop file for env specific. By doing that I was able to test one of exposed methods that read ldap directory...
I am sorry I got digressed but hope my point is clear at this point. I am not sure the way I handled this situation is right or wrong. I'd appreciate experienced engineers would clarify the way I handled the matter is acceptable in mockito way or not. If not, then plz advise me best way to handle it.
With Mockito,
a mock is an implementation of a wrapper class.
The mock object "wraps" the target of the mock
(the service in your example)
and allows you to define functionality of each method.
There are two mocked functionality options with Mockito;
call the wrapped method and don't call the wrapped method.
I don't know when it would make sense to call the wrapped method,
so I always use don't call the wrapped method.
After you create the mock,
use the Mockito.doReturn(returnvalue).when(mockObject).method(method parameters) method to mock functionality.
Edit: some more info.
I will assume that you are using junit v4.
The details of this will differ based on the the junit major release number,
but the actual work will be the same.
Use annotations to define your Mock objects (#Mock),
except in a few special cases.
This will create mocks of non-final classes,
abstract classes,
and interfaces.
Create a "before-test" method using the #Before annotation;
I traditionally name this method preTestSetup,
but the actual name does not matter.
Call MockitoAnnotations.initMocks(this) as the first line of code
in the "before-test" method.
This will find the #Mock annotations and instantiate a mock for each.
Use the ReflectionTestUtils.setField method to inject the mocks into your object (assuming that you don't have setter methods,
which I traditionally don't like).
Define the mocked functionality of each method using the Mockito.doReturn(returnvalue).when(mockObject).method(method parameters) technique.
Here is some example code
(caveat:
this should be fully functional,
but I did not compile it):
public interface MyService
{
String blammy(SomeParameter parameter);
}
public class UsesMyService
{
#Autowired
private MyService myService;
public String kapow(final SomeParameter parameter)
{
return myService.blammy(parameter);
}
}
public class UnitTestUsesMyService
{
private UsesMyService classToTest;
#Mock
private MyService mockMyService;
#Mock
private SomeParameter mockSomeParameter;
#Before
public void preTestSetup()
{
MockitoAnnotations.initMocks(this);
classToTest = new UsesMyService();
doReturn("Blam").when(mockMyService).blammy(mockSomeParameter);
ReflectionTestUtils.setField(
classToTest,
"myService",
mockMyService);
}
#Test
public void kapow_allGood_success()
{
final String actualResult;
actualResult = classToTest.kapow(mockSomeParameter);
assertNotNull(actualResult); // Not strictly necessary.
assertEquals(
"Blam",
actualResult);
}
}
I have a service ISOLanguageService with a method getDefaultLanguage();
I want to mock this service in one class ISOLanguageServiceMock in this way:
public class ISOLanguageServiceMock {
#Mock
private ISOLanguageService isoLanguageService;
public ISOLanguageServiceMock() {
MockitoAnnotations.initMocks(this);
ISOLanguage isoLanguage = new ISOLanguage();
isoLanguage.setLanguageCode("EN");
when(isoLanguageService.getDefaultLanguage()).thenReturn(isoLanguage);
}
Then i have other service UserService that uses this service isoLanguageService in one of its metdhods.
public void doSomtthing() {
return isoLanguageService.getDefaultLanguage()
}
I want to test the UserService but i want in someway to reuse the mock ISOLanguageServiceMock because it's going to be used in many other services.
I want Something like this
#RunWith(PowerMockRunner.class)
public class UserServiceTest {
private ISOLanguageServiceMock languageMock = new ISOLanguageServiceMock();
#InjectMocks
private UserService userService;
public void setUp() {
MockitoAnnotations.init(this)
}
public void testDoSomething() {
userService.doDomething();
}
}
I'd like that the mock for isoLanguageService be injected in the userService, but it's not...
Is there anyway to reuse a mocks ?? Do i have to write in every test class the mock for isoLanguageService ??
You can't reuse mocks this way. You need #Mock instances to be in your test case, and use them there.
Meaning:
#Mock
private ISOLanguageService isoLanguageService;
and specifications for into your UserServiceTest class.
Mockito does not understand (or care) that your ISOLanguageServiceMock class contains something that could be injected into the class under test.
Mockito looks for the mocks you have in your test class, and those get injected, nothing else!
Regarding the re-use aspect:
you could do that by subclassing (having a base class with that #Mock field)
but then, that is bad practice, to a certain degree. Unit tests should be self contained, as much as possible. It is okay when unit tests duplicate code, because you want to be able to look at one file (your test case) to understand what is going on).
Meaning: (in general), code duplication within unit tests isn't that crucial. The goal of unit tests is to enable quick debugging.
Well, some alternatives:
you can of course, not use #InjectMocks. In that case, your production code needs another way for you to inject mocked objects yourself (either setters, or test only constructors).
when you inject manually, you can of course inject whatever mock object you want to, even one that comes from another class
but then: no extra class required, simply have a static method somewhere that returns a (pre-configured) mock.
I have read quite a few articles/blog/StackOverflow questions, but the confusion regarding Mockito mock and spy still remains. So, I started trying implementing them in a small Spring Boot app. My app has a ProductRepository extending CrudRepository.
Currently I'm testing the repository by mocking ProductRepository as follows
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {RepositoryConfiguration.class})
public class ProductRepositoryMockTest {
#Mock
private ProductRepository productRepository;
#Mock
private Product product;
#Test
public void testMockCreation(){
assertNotNull(product);
assertNotNull(productRepository);
}
#Test
public void testSaveProduct() {
assertThat(product.getId(), is(equalTo(0)));
when(productRepository.save(product)).thenReturn(product);
productRepository.save(product);
//Obviously this will fail as product is not saved to db and hence
//#GeneratedValue won't come to play
//assertThat(product.getId() , is(not(0)));
}
#Test
public void testFindProductById() {
when(productRepository.findOne(product.getId())).thenReturn(product);
assertNotNull(productRepository.findOne(product.getId()));
assertEquals(product, productRepository.findOne(product.getId()));
}
}
The test passes. Is this the right way? I also want to understand how to use #Spy here and Why should I need it? Any specific scenarios related to this is most welcome.
Thanks in advance.
I have taken a look at your tests and there are few things to keep in mind (this is based on my experience so the final call is up to you):
1) Hamcrest - If that is possible i would strongly recommend using Hamcrest for your assert implementations.
First of all it is much more versatile and feature rich than the standard junit assertions.
Second of all you may one day have the need (as i did on one of my projects) to switch from junit to testng for examle.
Having all your assertions based on a xunit-neutral implementation, the switch will not be so painful.
2) Assertions - Instead of assertNull, assertEquals go for the hamcrest's assertThat(String description, T value, Mathcer<T> matcher);
Thanks to that you will get clear error messages when a test breaks.
3) Small tests - In your Repository test.. do not put all the cases in one test.
Try to create many small and simple tests for cases like: findOne.. count.. findAll etc.
Again it will be easier to find the problem when a small test like that breaks.
And if more cases will come you wont end up with a 200+ lines of a test case which is unacceptable
4) Naming - Do not name your tests as.. testXYZ.
It is obvious that these are test methods.
I would recommend using the BDD way of naming: shouldX_whenY_givenZ.
F.e. shouldReturnZeroCount_givenNoEntitiesInTheDatabase
5) Structure - Try to split each of your test implementation in three explicit sections, including comments for best result:
public void should..() throws Exception{
// Arrange
// when().then()
// mock()
// Act
// classUnderTest.process()
// Assert
// assertThat(..)
}
6) Do not split your test classes between Mock / Spy test. HAve one ImplTest.
7) Never mock a class which you are testing. In the worst case scenario use Spy if you have to mock some of the methods of the class under test.
The point of mocking is to isolate the implementation in the class under test, so that only that classes logic is invoked during the test.
Mock only dependencies of the class.
I am having a build failure issue while running a bunch of unit test over a java project. I am getting the NoClassDefFoundError which is happening because of the lack of ability for the unit test to get the dependencies. I am trying to mock an object for the class and then call the function, but the code is structured in a way that is getting a bit complex for me to handle the issue. I am very new to unit testing. I have provided below, a sample of code structure that my project has
Class ServiceProvider(){
obj declarations;
public void mainFunction(){
//Does a couple of things and calls a function in another class
boolean val = subFunction();
}
public boolean subFunction(){
boolean val = AnotherClass.someFunction(text);
//this function throws lots of exceptions and all those are caught and handled
return val;
}
#RunsWith(MockitoJUnitRunner.class)
Class UnitTestBunch(){
#Mock
AnotherClass acObj = new AnotherClass();
#InjectMock
ServiceProvider sp = new ServiceProvider();
#Test
public void unitTest1() throws Exception{
when(acObj.someFunction(text)).thenReturn(true);
}
#Test
public void unitTest2() throws Exception{
thrown.expect(ExceptionName.Class);
sp.mainFunction();
}
I have a test that uses the mock object and performs the function call associated with that class. But, the issue here is that there are a bunch of other unit test cases that are written similar to the unitTest2 function and calls the mainFunction at the end of the test. This mainFunction invokes someFunction() and causes NoCalssDefFoundError(). I am trying to make the unit test execute the content in unitTest1 everytime when it sees the AnotherClass.someFunction(). I am not sure if this is achievable or not. There could be another better way to resolve this issue. Could someone please pitch in some ideas?
In your test you seem to be using unitTest1 for setup, not for testing anything. When you run a unit test, each test should be able to run separately or together, in any order.
You're using JUnit4 in your tests, so it would be very easy to add the statement you have in unitTest1 into a #Before method. JUnit4 will call this method before each test method (annotated with #Test).
#Before
public void stubAcObj() throws Exception{
when(acObj.someFunction(text)).thenReturn(true);
}
The method may be named anything, though setUp() is a common name borrowed from a method to override in JUnit3. However, it must be annotated with org.junit.Before.
If you need this from multiple test cases, you should just create a helper, as you would with any code. This doesn't work as well with #InjectMocks, but you may want to avoid using #InjectMocks in general as it will fail silently if you add a dependency to your system-under-test.
public class AnotherClassTestHelper {
/** Returns a Mockito mock of AnotherClass with a stub for someFunction. */
public static AnotherClass createAnotherClassMock() {
AnotherClass mockAnotherClass = Mockito.mock(AnotherClass.class);
when(mockAnotherClass.someFunction(text)).thenReturn(true);
return mockAnotherClass;
}
}
As a side note, this is a counterintuitive pattern:
/* BAD */
#Mock
AnotherClass acObj = new AnotherClass();
You create a new, real AnotherClass, then instruct Mockito to overwrite it with a mock (in MockitoJUnitRunner). It's much better just to say:
/* GOOD */
#Mock AnotherClass acObj;
I have a simple unit test where in I test a DAO. I mock the dependency and inject it into the subject through the constructor.
Do I need a tear down? Does Mockito test exit at the same state it entered the setup method? Please also explain.
#Mock
private PersonDAO dao;
#Overide
public void setup(){
MockitoAnnotations.initMocks(this);
sut = new PersonResource(dao);
}
#Test
public void testUpdate(){
when(dao.findNameById(1)).thenReturn("Abhinav-before");
sut.update(1, "Abhinav-after");
}
Unless you're pulling in other state-driven resources, such as a cache, or a temp file, you don't need to tear down any resources when mocking.
A mock object is just an object; it doesn't have or maintain anything to external services. It will get garbage collected just like any other object you have in your test. Depending on how you're injecting the mock, it's recreated for every test run, anyway.
Now that you've provided a little bit of code, had you used the #Before annotation, you would be sure that both the mock gets injected before each instance of the test run. As it stands, that test probably doesn't compile; I can't imagine a scenario in which you would have that test extend another test that has a setup method.
(And if you do, please don't. You'll only hurt yourself.)
Lastly, assert something in this test. You're not asserting anything, so it'll always pass unless you assert something to be true about the state of your test object.
With that bit out of the way, if you use MockitoJUnitRunner instead, you don't require the initMocks piece, but this is only applicable if this is your only runner as JUnit can't support multiple runners.
#RunWith(MockitoJUnitRunner.class)
public class PersonResourceTest {
#Mock
private PersonDAO dao;
#InjectMocks
private PersonResource testObject;
#Test
public void testUpdate(){
when(dao.findNameById(1)).thenReturn("Abhinav-before");
testObject.update(1, "Abhinav-after");
}
}