One of the common questions in interview,have you written test cases for your Java Code.If your code uses some other class,how you resolved this dependency.
Have you used Stubs or Mocks and whats the reason behind it?
Is there any difference between them?
Lets discuss this scenario and figure out when to use what.
Use Case
We have to create authentication module in our system.It checks for username and password and returns true or false depending upon whether username and password supplied is correct
We have to create authentication module in our system.It checks for username and password and returns true or false depending upon whether username and password supplied is correct
or not.In our use case we have a LoginService which uses IUserDAO.There is a concrete class named UserDAO which implements IUserDAO and uses database table for doing authentication check.It will return success/failure as authentication result
So now if we have to write test case for LoginService authenticate () method.We need to provide some implementation for IUserDAO for test case to complete.We fake the IUserDAO implementation by creating a mock or stub of it.
What is Stub?
Stub is a fake implementation of the dependent class.If we follow interface driven approach we can create a stub by implementing the interface and provide hard coded return values.
The basic idea is to implement the dependencies as concrete classes,
which reveal only a small part of the overall behavior of the dependent
class, which is needed by the class under test.
+ves
-There is no dependency on external jars.
-We are writing extra class having redundant implementation and hard coded return values for testing our api.
-Easy to simulate and understand
-ves
-If interface changes we have to modify the stubs.
-There could be multiple stub implementations for testing different api's because if we use one stub class for all test case,we may break other test cases.
-If interface has many methods our stub will have lots of empty methods.
Above use case with Stub Implementation
package com.kunaal.stubMock.test; import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; import com.kunaal.stubMock.dao.IUserDAO; import com.kunaal.stubMock.service.LoginService; /** * @author Kunaal A Trehan * */ public class LoginServiceTest { private LoginService loginService=new LoginService(); /** * Here we setting stub implementation for userDAO which we will use in this service * So interface driven approach helps us to fake the dependency by injecting * stub[anonymous implementation of IUserDAO] of other class and let us test * our method */ @Before public void stubSetup(){ loginService.setUserDAO(new IUserDAO(){ public boolean authenticate(String uName, String passWd) { if(uName!=null && uName.equals("Kunaal") && passWd !=null && passWd.equals("Password")) return true; else return false; } }); } @Test public void authenticate(){ assertTrue(loginService.authenticate("Kunaal", "Password")); assertFalse(loginService.authenticate("Kunaal", "Kunaal")); } }
What is Mock?
Mock also fake's the implementation .But in case of mock we record and verify the interaction between the two classes.Basic idea is to plug the expectation at the runtime and verify the same.
+ves
-No need to create an extra class for faking the implementation
-Relives us from having blank implementations for methods in case number of methods are huge.
-We can define the expectation at the run time
-We can verify whether the method in the dependent class has actually been invoked or not
-ves
-Need third party api for providing mocking behavior
-Its not straight forward to understand
Above use case with mock implementation
package com.kunaal.stubMock.test; import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.verify; import static org.junit.Assert.assertTrue; import org.junit.Before; import org.junit.Test; import com.kunaal.stubMock.dao.UserDAO; import com.kunaal.stubMock.service.LoginService; /** * @author Kunaal A Trehan * */ public class MockLoginServiceTest { private LoginService loginService; private UserDAO mockUserDAO; @Before public void setup(){ loginService=new LoginService(); mockUserDAO=createMock(UserDAO.class); loginService.setUserDAO(mockUserDAO); } @Test public void authenticate(){ //push the expectations and other information // Set expectations on mocks. expect(mockUserDAO.authenticate("Kunaal","Password")). andReturn(true); // Set mocks into testing mode. replay(mockUserDAO); assertTrue(loginService.authenticate("Kunaal", "Password")); //assertFalse(loginService.authenticate("Kunaal", "Kunaal")); verify(mockUserDAO); } }
So final word whats the difference between these two.As per my understanding mock is generated at the run time and it helps to test the state as well as interaction behavior between two classes.This is not possible in stub implementation as there is no way to verify whether the particular method in the dependent class has been invoked by the test class or not.
However I can be wrong.Do let me know if my understanding is not right.
No comments:
Post a Comment