I'm new to mock testing.
I want to test my Service method CorrectionService.correctPerson(Long personId).
The implementation is not yet written but this it what it will do:
CorrectionService will call a method of AddressDAO that will remove some of the Adress that a Person has. One Person has Many Addresses
I'm not sure what the basic structure must be of my CorrectionServiceTest.testCorrectPerson.
Also please do/not confirm that in this test i do not need to test if the adresses are actually deleted (should be done in a AddressDaoTest), Only that the DAO method was being called.
Thank you
Cleaner version:
#RunWith(MockitoJUnitRunner.class)
public class CorrectionServiceTest {
private static final Long VALID_ID = 123L;
#Mock
AddressDao addressDao;
#InjectMocks
private CorrectionService correctionService;
#Test
public void shouldCallDeleteAddress() {
//when
correctionService.correct(VALID_ID);
//then
verify(addressDao).deleteAddress(VALID_ID);
}
}
A simplified version of the CorrectionService class (visibility modifiers removed for simplicity).
class CorrectionService {
AddressDao addressDao;
CorrectionService(AddressDao addressDao) {
this.addressDao;
}
void correctPerson(Long personId) {
//Do some stuff with the addressDao here...
}
}
In your test:
import static org.mockito.Mockito.*;
public class CorrectionServiceTest {
#Before
public void setUp() {
addressDao = mock(AddressDao.class);
correctionService = new CorrectionService(addressDao);
}
#Test
public void shouldCallDeleteAddress() {
correctionService.correct(VALID_ID);
verify(addressDao).deleteAddress(VALID_ID);
}
}
Related
I am writing a test using Junit + Mockito + Powermock.
I have a class like following which I want to test:
public class MyUtils {
public static Object method1() {} //I want to mock this only
public static void method2() {} //I want to keep this as is during my test.
public static void method3() {} //I want to keep this as is during my test.
}
I want to mock only method1 but not method2 or method3.
#RunWith(PowerMockRunner.class)
#PrepareForTest(MyUtils.class)
public class MyTest {
#Before
public void setUpBeforeClass() throws Exception {
PowerMockito.mockStatic(MyUtils.class);
}
#Test
public void test1() throws Exception {
when(MyUtils.method1()).thenReturn(something);
MyUtils.method3(); //method3 is getting mocked with an empty implementation by PowerMockito
}
...
}
Can I have some methods mocked and some not be mocked i.e. they keep their original implementation during the test? Is this possible with Mockito + Powermock?
My test may not look very elegant but I have simplified my usecase before posting here.
Thank you.
Yes it is possible to mock static methods using Powermock and JUnit as below:
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.powermock.api.mockito.PowerMockito.*;
#RunWith(PowerMockRunner.class)
#PrepareForTest(IDGenerator.class)
public class UserDAOTest {
#Test
public void createShouldReturnAUserId() {
UserDAO dao = new UserDAO();
mockStatic(IDGenerator.class);
when(IDGenerator.generateID()).thenReturn(1);
int result = dao.create(new User());
assertEquals(1, result);
verifyStatic();
}
}
public final class IDGenerator {
static int i;
public static final int generateID() {
return i++;
}
}
public class UserDAO {
public int create(User user){
int id = IDGenerator.generateID();
//Save the user object to the db
return id;
}
}
public class User {
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
Hope it helps!
If you have way more methods that you want to keep with real implementation than ones that need to be mocked (especially when its only one in your case) then I would go for spy instead of mock:
import static org.powermock.api.mockito.PowerMockito.spy;
#RunWith(PowerMockRunner.class)
#PrepareForTest(MyUtils.class)
public class MyTest {
#Before
public void setUpBeforeClass() throws Exception {
spy(MyUtils.class);
}
#Test
public void test1() throws Exception {
doReturn(something).when(MyUtils.class, "method1");
MyUtils.method3(); // this will be a real call
}
...
}
Now all the methods except method1 will be called with real implementation.
I have below class scenario. While testing MyTestableClass, I wish to process Autowired class.
I would like to mock only variable in AutoWired class.
sample class is as below-
public class MyTestableClass {
#Autowired
private MyServiceClass service;
public void handleError(){
...
service.doSomething();
}
}
public class MyServiceClass {
#Autowired
private JMSChannel channel;
public void doSomething(){
System.out.println("Inside Service class");
.....
channel.isAvailable();
.....
}
}
#RunWith(MockitoJUnitRunner.class)
public class MyTestableClassTest {
private MyTestableClass testClass= new MyTestableClass();
private JMSChannel channel;
#Before
public void init(){
channel= mock(JMSChannel.class);
when(channel.isAvailable()).thenReturn(Boolean.TRUE);
}
#Test
public void test(){
testClass.handleError();
}
}
For example, Console should give me "Inside Service class" before returning true.
Thanks in Advance !
You need to create and instance of your service (or a mock of it) and set its channel to your mocked one, then set MyTestableClass#service to this one. Something like:
#Before
public void init(){
channel= mock(JMSChannel.class);
when(channel.isAvailable()).thenReturn(Boolean.TRUE);
MyServiceClass service = new MyServiceClass();
ReflectionTestUtils.setField(service, "channel", channel);
myTestableClass = new MyTestableClass();
ReflectionTestUtils.setField(myTestableClass, "service", service);
}
with ReflectionTestUtils from spring-test (NB: you can use a setter instead)
I am newbie in Java world, but it is very hard understand why not can I stub method of a mocked object...
#RunWith(MockitoJUnitRunner.class)
public class ChildBLLIT extends BaseInteractorIT {
#InjectMocks
private ChildBLL ChildBLL = Mockito.mock(ChildBLL.class);
#Before
public void setUp() {
ChildBLL.engine = engineMock;
}
/**
* Test of getZipStatistics method, of class ChildBLL.
*/
#Test
public void testGetZipStatistics() {
final String testZipStatisticsText = "DummyZipStatistics";
//This method will throw the null pointer exception
when(ChildBLL.engine.getZIPStatistics()).thenReturn(testZipStatisticsText);
ChildBLL.getZipStatistics();
verify(ChildBLL.engine).getZIPStatistics();
}
}
When I try to stub the getZIPStatistics() method I get always a null pointer exception, of course I get, because in the getZIPStatistics() method there is an private object, which is not mocked... it seems to me the Mockito does not mocking the private fields... and unfortunately this is from another project:
public class BaseIT {
#Mock
protected static FromOtherProject engineMock;
#Before
public void initMocks() {
MockitoAnnotations.initMocks(this);
}
}
Here I mocked the engine variable, but then how can I mock/stub the getZIPStatistics() method? This is this method:
public class FromOtherProject {
//...
public final String getZIPStatistics() {
return ZIPStatistics.toString();
}
}
What can I do?
Let's assume a simple class...
public class Account {
public String getPassword() {
return "abc";
}
}
...and simple class that contains it...
public class AccountHolder {
private Account account;
public String getAccountPassword() {
return this.account.getPassword();
}
}
So now we have a simple base class for all Account based tests...
public class AccountBasedTest {
#Mock
protected Account account;
}
...and a class that actually tests the AccountHolder...
#RunWith(MockitoJUnitRunner.class)
public class AccountHolderTest extends AccountBasedTest {
#InjectMocks
private AccountHolder accountHolder;
#Test
public void getAccountPasswort_must_return_account_password() {
Mockito.when( this.account.getPassword() ).thenReturn ("xyz");
Assert.assertEquals("xyz", this.accountHolder.getAccountPassword());
}
}
And that's all. The #InjectMocks, etc. annotations will also look in the superclasses, so you get your mocked account and that account will be put into your AccountHolder. No need to call MockitoAnnotations.initMocks. It shouldn't hurt, but it's not needed because you are using the MockitoJUnitRunner already, which does exactly that.
I'm looking for a way in JMockit to inject the private fields inside a class while maintaining the ability to trigger the real methods. I use #Injectable and #Tested offered by JMockit. But somehow after that the injected instance is not able to call the real method.
Example test:
public class TestClass {
public static class DoSomething {
private Call callee;
public void execute() {
callee.call();
}
}
public static class Call {
public void call() {
System.out.println("real");
}
}
#Tested DoSomething doSomething;
#Injectable Call call;
// nothing happens
#Test
public void testRealCall() {
doSomething.execute();
}
// invocation doesn't help either
#Test
public void testRealCallSecondTry() {
new MockUp<Call>() {
#Mock
#SuppressWarnings("unused")
public void call(Invocation inv) {
inv.proceed();
}
};
doSomething.execute();
}
// this works, but requires redundant methods
#Test
public void testRealCallThirdTry() {
new MockUp<Call>() {
#Mock
#SuppressWarnings("unused")
public void call() {
System.out.println("real");
}
};
doSomething.execute();
}
#Test
public void testFakeCall() {
new MockUp<Call>() {
#Mock
#SuppressWarnings("unused")
public void call() {
System.out.println("fake");
}
};
doSomething.execute();
}
}
Here DoSomething wraps the Call instance, which provides a way to print a message. The ideal output of the four test cases would be:
real
real
real
fake
However the actual scenario is that only 3 and 4 worked, printing:
real
fake
This shows if an instance is created using #Injectable. It's not able to directly call the original method without copying and pasting the old method body to the mocked version. That seems really awkward. Is there a workaround of this?
My understanding is that if you use #Injectable you just get an empty mock and then you can no longer call the original method.
The workaround that I would use is to do the injection "manually" like this:
public class TestClass {
public static class DoSomething {
private Call callee;
public void execute() {
callee.call();
}
}
public static class Call {
public void call() {
System.out.println("real");
}
}
#Tested DoSomething doSomething;
//#Injectable Call call;
// nothing happens
#Test
public void testRealCall() {
Deencapsulation.setField(doSomething, "callee", new Call());
doSomething.execute();
}
// invocation doesn't help either
#Test
public void testRealCallSecondTry() {
new MockUp<Call>() {
#Mock
#SuppressWarnings("unused")
public void call(Invocation inv) {
inv.proceed();
}
};
Deencapsulation.setField(doSomething, "callee", new Call());
doSomething.execute();
}
// this works, but requires redundant methods
#Test
public void testRealCallThirdTry() {
new MockUp<Call>() {
#Mock
#SuppressWarnings("unused")
public void call() {
System.out.println("real");
}
};
Deencapsulation.setField(doSomething, "callee", new Call());
doSomething.execute();
}
#Test
public void testFakeCall() {
new MockUp<Call>() {
#Mock
#SuppressWarnings("unused")
public void call() {
System.out.println("fake");
}
};
Deencapsulation.setField(doSomething, "callee", new Call());
doSomething.execute();
}
}
I ran into this question when I had the same problem. However, the existing answer don't work with newer versions of JMockit.
If a field in the tested class is annotated with #Inject, a corresponding #Injectable is required in the test class. Usually. This means that removing the #Injectable and instead mock the class with MockUp suggested in the other answer doesn't work. JMockit will complain with "Missing #Injectable for field ...".
What needs to be done instead is to change the #Injectable annotation to a #Tested annotation, i.e. change this
#Injectable Call call;
to
#Tested Call call;
call becomes a real instance and JMockit doesn't complain about a missing #Injectable. If you need to mock some methods in call, it can be done with MockUp as usual.
new MockUp<Call>() {
#Mock
public void someMethodToMock() {
}
};
I'm using EasyMock(version 2.4) and TestNG for writing UnitTest.
I have a following scenario and I cannot change the way class hierarchy is defined.
I'm testing ClassB which is extending ClassA.
ClassB look like this
public class ClassB extends ClassA {
public ClassB()
{
super("title");
}
#Override
public String getDisplayName()
{
return ClientMessages.getMessages("ClassB.title");
}
}
ClassA code
public abstract class ClassA {
private String title;
public ClassA(String title)
{
this.title = ClientMessages.getMessages(title);
}
public String getDisplayName()
{
return this.title;
}
}
ClientMessages class code
public class ClientMessages {
private static MessageResourse messageResourse;
public ClientMessages(MessageResourse messageResourse)
{
this.messageResourse = messageResourse;
}
public static String getMessages(String code)
{
return messageResourse.getMessage(code);
}
}
MessageResourse Class code
public class MessageResourse {
public String getMessage(String code)
{
return code;
}
}
Testing ClassB
import static org.easymock.classextension.EasyMock.createMock;
import org.easymock.classextension.EasyMock;
import org.testng.Assert;
import org.testng.annotations.Test;
public class ClassBTest
{
private MessageResourse mockMessageResourse = createMock(MessageResourse.class);
private ClassB classToTest;
private ClientMessages clientMessages;
#Test
public void testGetDisplayName()
{
EasyMock.expect(mockMessageResourse.getMessage("ClassB.title")).andReturn("someTitle");
clientMessages = new ClientMessages(mockMessageResourse);
classToTest = new ClassB();
Assert.assertEquals("someTitle" , classToTest.getDisplayName());
EasyMock.replay(mockMessageResourse);
}
}
When I'm running this this test I'm getting following exception:
java.lang.IllegalStateException: missing behavior definition for the preceding method call getMessage("title")
While debugging what I found is, it's not considering the mock method call
mockMessageResourse.getMessage("ClassB.title") as it has been called from the construtor (ClassB object creation).
Can any one please help me how to test in this case.
Thanks.
You need to call EasyMock.replay(mock) before calling the method under test. After calling the method under test you can call EasyMock.verify(mock) to verify the mock is called.
Next you need to add another expect call with the "title" argument since you call it twice.
Code:
EasyMock.expect(mockMessageResourse.getMessage("title")).andReturn("title");
EasyMock.expect(mockMessageResourse.getMessage("ClassB.title")).andReturn("someTitle");
EasyMock.replay(mockMessageResourse);
clientMessages = new ClientMessages(mockMessageResourse);
classToTest = new ClassB();
Assert.assertEquals("someTitle" , classToTest.getDisplayName());
EasyMock.verify(mockMessageResourse);
In my case, it was caused by the omission of a return value specification (andReturn(...)).
http://www.smcmaster.com/2011/04/easymock-issue-1-missing-behavior.html for more details.
This can have various causes (someMock is the name of your mocked Object in this answer).
On the one side it can be that you need to expect the call via
expect(someMock.someMethod(anyObject()).andReturn("some-object");
like in Reda's answer.
It can also be that you forgot to call replay(someMock) before you used the mock, like you can see in Julien Rentrop's answer.
A last thing that is possible that wasn't mentioned here is that you used the mock somewhere else before in a test and forgot to reset the mock via reset(someMock).
This can happen if you have multiple Unit Tests like this:
private Object a = EasyMock.createMock(Object.class);
#Test
public void testA() throws Exception {
expect(a.someThing()).andReturn("hello");
replay(a);
// some test code and assertions etc. here
verify(a);
}
#Test
public void testB() throws Exception {
expect(a.someThing()).andReturn("hello");
replay(a);
// some test code and assertions etc. here
verify(a);
}
This will fail on one test with the IllegalStateException, because the mock a was not reset before being used in the next test. To solve it you can do the following:
private Object a = EasyMock.createMock(Object.class);
#Test
public void testA() throws Exception {
expect(a.someThing()).andReturn("hello");
replay(a);
// some test code and assertions etc. here
verify(a);
}
#Test
public void testB() throws Exception {
expect(a.someThing()).andReturn("hello");
replay(a);
// some test code and assertions etc. here
verify(a);
}
#After
public void tearDown() throws Exception {
reset(a); // reset the mock after each test
}
You should put your call to replay after the expect calls, and before you use your mock. In this case you should change your test to something like this:
#Test
public void testGetDisplayName()
{
EasyMock.expect(mockMessageResourse.getMessage("ClassB.title")).andReturn("someTitle");
EasyMock.replay(mockMessageResourse);
clientMessages = new ClientMessages(mockMessageResourse);
classToTest = new ClassB();
Assert.assertEquals("someTitle" , classToTest.getDisplayName());
}
For me, this exception was occurring because the method I was trying to stub was final (something I hadn't realized).
If you want to stub a final method you'll need to use Powermock.