Today I learned about Mockito and while playing around with it I found something I do not understand.
Say I would like to test the following piece of code:
public void stop(boolean showMessage) {
if(executor != null && !executor.isShutdown() && this.isRunning) {
if(showMessage) {
View.getSingleton().showMessageDialog(Constant.messages.getString("sessionchecker.stopmessage"));
}
executor.shutdownNow();
executor = null;
extension.getCountdownTimer().stopCountdown();
this.isRunning = false;
this.usersReady.clear();
}
}
Since the stop method is a void I would need to call doAnswer (If I understand correctly).
So I tried the following:
#Test
public void testStopIsRunningFalse() {
Mockito.when(controller.isRunning()).thenReturn(true); // Mock a running service
Mockito.doAnswer(new Answer<Void>() {
#Override
public Void answer(InvocationOnMock invocation) throws Throwable {
if(controller.isRunning()) {
// Normally would actually shut down service
Mockito.when(controller.isRunning()).thenReturn(false); // Service should stop
}
return null;
}
}).when(controller).stop(false);
controller.stop(false);
boolean expected = false;
assertEquals(expected, controller.isRunning());
}
I, however, do not understand what the purpose of a test like this would be. Why would I test it like this since this will never fail (the parameter isRunning is being set as I would expect it to be).
Basically I only need to test the state of certain fields (isRunning and executor for example). These fields do not have public getters or setters however..
Therefore, I think I misunderstand the usage of the deAnswer. Could someone help me out?
If I understand your code example, it appears you are mocking the object you want to test, which is a no-no 99.9% of the time. You generally only want to mock direct collaborators of the class you are testing. Collaborators consist of things such as injected services (or other injected fields), and arguments of the method you are testing -- essentially anything that represents initial state of your class under test before you invoke the method being tested.
Related
There are considerable answers around, that seem to address this topic, but somehow it is never working out for me. I must be making some mistake, somewhere.
I have this class.
public class myClass {
public static void myEdit(boolean flag) throws Exception {
if (flag) {
System.out.println("Wow!");
} else {
PortalBL.mySave(flag);
}
}
public static void mySave(boolean wtv) throws Exception {
System.out.println("Doesn't matter");
}
}
I want to write a simple unit test, where I call myEdit, with flag = false. I just want the test to pass if it confirms that the PortaBL.mySave was called. I don't want it to be executed, I just want to verify if it was called.
I am trying to do it like this:
#Test
public void myTest() throws Exception {
try (MockedStatic<PortalBL> mock = Mockito.mockStatic(PortalBL.class)) {
mock.when(() -> PortalBL.mySave(anyBoolean())).thenAnswer((Answer<Void>) invocation -> null);
PortalBL.myEdit(false);
mock.verify(() -> PortalBL.mySave(anyBoolean()));
}
}
The idea would be to mock the static method, so that I can handle it without executing it and later verify that it was called, when I call PortalBL.myEdit
I believe that the class is badly written. It shouldn't be static method, I should be instantiating this class as an object and carry on. But, let's say that we are determined to test this particular scenario, as it is. Is it possible?
Btw, when I execute the PortaBL.myEdit(false) line, it isn't truly executed. I believe it is because the machine is thinking it is a mock, and doesn't know what to do with it when it is called..
I'm using Mockito to test a method that internally makes a networking call and returns a value based on the result of the networking call. This method uses a SynchronousQueue to wait for the result, and the result is set by the callback for the networking call:
HelperClass helperClassObject = new HelperClassObject();
...
public SomeResultCode methodWithNetworkCall() {
SynchronousQueue<SomeResultCode> resultQueue = new SynchronousQueue<>();
// some condition checking code
helperClassObject.makeNetworkCall(new GenericCallback() {
#Override
public void onSuccess(JSONObject response) {
resultQueue.offer(SomeResultCode.SUCCESS);
}
#Override
public void onFailure(VolleyError error) {
resultQueue.offer(SomeResultCode.FAILURE);
}
});
SomeResultCode resultCode = null;
try {
resultCode = resultQueue.poll(1, TimeUnit.MINUTES);
} catch (InterruptedException e) {
}
return resultCode == null ? SomeResultCode.FAILURE : resultCode;
}
In one of my unit test methods I'm trying to verify that SUCCESS is returned upon successful network call. I've tried using ArgumentCaptor and doAnswer to trigger the callback's onSuccess. However, the method is returning FAILURE. I put a breakpoint in the onSuccess, and it looks like when I use the ArgumentCaptor way the onSuccess is triggered AFTER the poll has timed out. When I use the doAnswer way, I see onSuccess called during the setup (doAnswer.when) but not after I actually call the method. What am I doing wrong?
EDIT
Stepping through the code again, it looks like answer is called from within the method I'm testing (i.e. when I call testObject.methodWithNetworkCall during my test), NOT during setup. So it is doing exactly what it is supposed to do: responding with onSuccess. But it is responding with onSuccess BEFORE poll is called. So it seems the problem is not that answer and mocking in general is not working/set up wrong, it is an issue with testing with SynchronousQueue.
Here is my test code:
public class TestClassUnitTest {
TestClass sut;
HelperClass helperClassObject = mock(HelperClass.class);
#Before
public void setup() {
sut = new TestClass();
injectField(sut, "helperClassFieldName", helperClassObject);
}
public void injectField(Object testObject, String fieldName, T mockToInject) {
// some code using reflection to inject the mock object into the test object
}
#Test
public void testMethodWithNetworkCallWithCaptor() {
ArgumentCaptor<GenericCallback> captor = ArgumentCaptor.forClass(GenericCallback.class);
SomeResultCode result = sut.methodWithNetworkcall();
verify(helperClassObject, times(1)).makeNetworkCall(captor.capture());
captor.getValue().onSuccess(new JSONObject());
Assert.assertEquals(SomeResultCode.SUCCESS, result);
}
#Test
public void testMethodWithNetworkCallWithDoAnswer() {
doAnswer(new Answer(){
#Override
public Object answer(InvocationOnMock invocation) throws Throwable {
((GenericCallback)invocation.getArguments()[0]).onSuccess(new JSONObject());
return null;
}
}).when(helperClassObject).makeNetworkCall(any(GenericCallback.class));
SomeResultCode result = sut.methodWithNetworkcall();
Assert.assertEquals(SomeResultCode.SUCCESS, result);
}
}
It looks like you're not replacing your HelperClassObject in your system-under-test, or at least you haven't shown us where you have. The mock returned by Mockito.mock (or #Mock or spy or #Spy) doesn't apply to every instance of the class you pass in; it just creates a single instance. You have to make sure to set the instance (HelperClassObject here) in your system-under-test, possibly by passing it in as a constructor parameter, setting the instance as a field, or setting it using a setter method. If you leave it as new HelperClassObject() as you've shown us, there's no way Mockito will be able to help you.
Your reference to "onSuccess called during the setup (doAnswer.when)" worries me a little bit, because if you've created a mock using Mockito.mock, there should be no reason Mockito would actually call your Answer during setup. This leads me to believe that your HelperClassObject or makeNetworkcall method can't be mocked, possibly from having limited visibility, or because they're marked static or final. Mockito effectively works by writing a custom subclass of the class you're mocking, so make sure the classes and methods you're mocking are public and non-final to ensure they're overridable. (It is possible to mock protected or package-private methods, but certain versions of Mockito have complications with certain code structures. Let's rule that out first.)
After you make sure that the class is mockable and that it's using the mocked HelperClassObject instance you pass in, you'll be able to move forward. You'll want to pursue the doAnswer structure: The ArgumentCaptor version won't work, because if your methodWithNetworkcall blocks and waits for a result, then you'll get a FAILURE return value before you ever get a chance to verify and call your callback. (That explains the timeout.) In other cases where your method-under-test can return first, the ArgumentCaptor solution will be more practical for you.
In this case using doAnswer IS the correct approach. The issue is with the way SynchronousQueue worked: it expects multi-threaded usage of this queue:
A blocking queue in which each insert operation must wait for a corresponding remove operation by another thread, and vice versa.
But in this testing case the test runs on a single thread.
Solution: mock the SynchronousQueue, and use doAnswer to get offer() and poll() to push/pop result onto a LinkedList. In the process, I also moved the SynchrnousQueue local variable resultQueue out of methodWithNetworkCall() and made it an instance member. Updated test code below:
public class TestClassUnitTest {
TestClass sut;
private LinkedList testQueue = new LinkedList();
private SynchronousQueue<SomeResultCode> resultQueueMock = mock(SynchronousQueue.class);
private HelperClass helperClassMock = mock(HelperClass.class);
#Before
public void setup() {
sut = new TestClass();
injectField(sut, "resultQueue", resultQueueMock);
injectField(sut, "helperClassFieldName", helperClassMock);
}
public void injectField(Object testObject, String fieldName, T mockToInject) {
// some code using reflection to inject the mock object into the test object
}
#Test
public void testMethodWithNetworkCallWithDoAnswer() {
doAnswer(new Answer(){
#Override
public Object answer(InvocationOnMock invocation) throws Throwable {
((GenericCallback)invocation.getArguments()[0]).onSuccess(new JSONObject());
return null;
}
}).when(helperClassMock).makeNetworkCall(any(GenericCallback.class));
mockQueue();
SomeResultCode result = sut.methodWithNetworkCall();
Assert.assertEquals(SomeResultCode.SUCCESS, result);
}
private void mockQueue() {
doAnswer(new Answer() {
#Override
public Object answer(InvocationOnMock invocation) throws Throwable {
testQueue.push(((SchedulableJob.Result)invocation.getArguments()[0]));
return true;
}
}).when(resultQueueMock).offer(any());
try {
doAnswer(new Answer() {
#Override
public Object answer(InvocationOnMock invocation) throws Throwable {
if (testQueue.size() > 0) {
return testQueue.pop();
} else {
return null;
}
}
}).when(resultQueueMock).poll(1, TimeUnit.MINUTES);
} catch (InterruptedException e) {
}
}
}
I have started learning JUNIT.
Here is what i am trying to achieve.
I have a class which checks if the inputString is part of secretKey;
public class StringChecker {
public boolean isEqual(String name)
{
boolean isEqual = false;
if(getSecretKey().contains(name))
{
isEqual = true;
}
return isEqual;
}
public String getSecretKey()
{
return "OSKAR";
}
}
My test class is this
public class RandomCheck {
#Test
public void isEqualTest()
{
StringChecker stringChecker = mock(StringChecker.class);
when(stringChecker.getSecretKey()).thenReturn("james");
//assertEquals(true, new StringChecker().isEqual("OSKAR")); <----this test case passes
assertEquals(true, stringChecker.isEqual("james"));
}
}
When i use Mocked object it does not give me the expected result, hence failing the test. But when i use a real object it gives me expected result and passes the test.
Am i missing anything? Like any annotation
A mockito mock is an object having the interface of the mocked class, but not its implementation. Your StringChecker is mocked, meaning there is no implementation code making calls from isEqual to getSecretKey as you assume.
You could use mockito spy, See this SO question:
Mockito.spy() is a recommended way of creating partial mocks. The reason is it guarantees real methods are called against correctly constructed object because you're responsible for constructing the object passed to spy() method.
ROOKIE MISTAKE
Here's the rookie mistake i did (mentioned by Arnold).
I mocked the StringChecker class but i did not provide any implementation for isEqual(String) method.
And because there was no implementation, i was getting the default value. In this case false (return type of method is boolean).
Solution
Using static method spy(). (Again mentioned by #Arnold).
So here is what my working code looks like.
#Test
public void isEqualTest()
{
StringChecker stringChecker = new StringChecker();
StringChecker spy = spy(stringChecker);
when(spy.getSecretKey()).thenReturn("james"); // providing implementation for the method
assertEquals(true, spy.isEqual("james"));
}
What i learnt from it.
Just by mocking an object does not get your things done if you intend to use methods of mocked object (In simple terms PROVIDE IMPLEMENTATION for methods of mocked objects).
TIP
If you want to see the default value returned by mocked object, just call the method of mocked object in sysout(without giving implementation).
Hope it will help someone like me.Peace
An alternative way without mocking and with additional test cases:
#Test
public void isEqualTest() {
StringChecker stringChecker = new StringChecker() {
#Override
public String getSecretKey() {
return "james";
}
};
assertTrue(stringChacker.isEqual("james"));
assertTrue(stringChacker.isEqual("jam"));
assertTrue(stringChacker.isEqual("mes"));
assertFalse(stringChacker.isEqual("oops"));
}
BTW, the isEqual() can be simplified to one line:
public boolean isEqual(String name) {
return getSecretKey().contains(name);
}
Which are differences between andAnswer() and andDelegateTo() methods in EasyMock in terms of usage?
First difference
I know that when andAnswer method is used, it is skipped the constructor call. This is important if the constructor makes extra things.
class Dummy {
public Dummy(Object someArgument) {
// some validations of arguments
System.out.println("the constructor is called");
}
public Object method() {
System.out.println("the method is called");
return new Object();
}
}
#Test
public void testSt1() {
Dummy mock = EasyMock.createMock(Dummy.class);
EasyMock.expect(mock.method()).andAnswer(new IAnswer<Object>() {
#Override
public Object answer() throws Throwable {
System.out.println("mocked method is called");
return new Object();
}
} );
EasyMock.replay(mock);
mock.method();
}
#Test
public void testSt2() {
Dummy mock = EasyMock.createMock(Dummy.class);
EasyMock.expect(mock.method()).andDelegateTo(new Dummy(new Dummy(new Object()) {
#Override
public Object method() {
System.out.println("mocked method is called");
return new Object();
}
} );
EasyMock.replay(mock);
mock.method();
}
Results:
testSt1() does not call the constructor of Dummy
testSt2() calls the constructor of Dummy
What are the other differences?
The purpose of the two methods is to provide different levels of responsibility for your tests. Your example isn't that great, though.
Here's a simple method that demonstrates how functionally these two provide different test expectations.
public String foo() throws Exception {
throw new Exception();
}
With andAnswer, you can make a mocked version of this method return a String, even though it would never return one in practice. Your use of andAnswer implies an expected response.
With andDelegateTo, this will always throw an Exception. Your use of andDelegateTo implies an actual response.
andAnswer means your test-specific code will handle the response. For example, if you create a ParrotAnswer for a MockDao update method, the Parrot will return the updated Object, but no Dao is actually instantiated in the process. This is nice for unit testing where you basically walk the test subject through, but doesn't help if your mocked method doesn't do as what you method actually does.
andDelegateTo allows you to provide an actual Object implementing the interface to handle the response. We're allowing our test subject controlled access to a resource, rather than providing unrestricted access to a full resource. benefit of this is that you can test integration into a test environment, but minimize actual changes to the test environment. For example, you can delegate get to a wired Dao to fetch an actual live value from the Db, and mock the delete method, so you don't actually delete that same value during testing (and having to recreate it again later to do the same test if it has a static id, for example).
I am following an older Java tutorial that is teaching the concept of the Service layer, my program is a very simple program that will create a list of Bills and their due dates. Where I am stuck is in creating the JUnit Test for factory methods.
First here is the Bill Constructor
public Bill(String bname, Double bamount, Date bdate, String bfrequency){
this.billName = bname;
this.billAmount = bamount;
this.billDueDate = bdate;
this.frequency = bfrequency;
}
Next is the Interface to save and get these bills
public interface IBill {
public void save(Bill bill);
public Bill read(Bill readbill);
}
Bear with me, next is the concrete implementation of the interface which are stubbed out for now, nothing implemented yet
public class BillSvcImpl implements IBill {
#Override
public void save(Bill bill) {
System.out.println("Entering the Store BillInfo method");
}
#Override
public Bill read(Bill readbill) {
System.out.println("Entering the Read BillInfo method");
return null;
}
}
Then there is the factory method that will create/call the concrete implementation
public class Factory {
public IBill getBillInfo(){
return new BillSvcImpl();
}
}
Then finally the JUnit test where I am stucked
public class BillSvcTest extends TestCase {
private Factory factory;
#Before
public void setUp() throws Exception {
super.setUp();
factory = new Factory();
}
#test
public void testSaveBill(){
IBill bill = factory.getBillInfo();
Bill nanny = new Bill("Nanny",128d,new Date(6/28/2013),"Montly");
bill.save(nanny);
//what goes here??, Assert??
}
#test
public void testReadBill(){
//How can I write a Test for this??
//Please help
}
}
The instruction is
Create a JUnit Test for your service, The test should use the Factory to get the service, instantiated in the setUp() method.
My service/interface have two methods save and get, how can I create a test for these before I start the actual implementation.
Any help is appreciated.
Thanks
First, don't extend TestCase - instead, use JUnit 4.x.
Second, I take great umbrage against a method with side effects. There's no reason to modify your save method to return a boolean instead of void; you just have to take an alternative approach to testing the method.
Third, I'm of the persuasion that a simple unit test won't be able to cover the save functionality of this method. Something that reads like it would be persisted someplace is better suited for an integration test of some kind (using the database, ensuring that the file exists and the contents are correct, etc).
The main question you want to answer when you're unit testing is, "What is the expected result of this method invocation given this parameter?" When we call save, what do we expect to happen? Do we write to a database? Do we serialize the contents and write to a file? Do we write XML/JSON/plain text out? That would have to be answered first, and then could a useful test be written around it.
The same thing applies for read - what do I expect to receive as input when I attempt to read a bill? What do I gain from passing in a Bill object, and returning a Bill object? (Why would an outside caller have a notion of a bill that I'm trying to read?)
You have to flesh out your expectations for these methods. Here's an approach I use to write unit tests:
Given a specific input,
when I call this method,
then I expect these things to be true.
You have to define your expectations before you can write the unit tests.
IMO save method should return something to say whether Bill got saved or not. I would have kept save method like this
public boolean save(Bill bill) {
System.out.println("Entering the Store BillInfo method");
boolean result = false;
try {
//..... saving logic
result = true;
}
catch(Exception e) {
result = false;
e.printStackTrace();
}
return result;
}
and did an assert in the testcase as
#Test
public void testSaveBill(){
//Success
IBill bill = factory.getBillInfo();
Bill nanny = new Bill("Nanny",128d,new Date(6/28/2013),"Montly");
assertTrue(bill.save(nanny));
//Failure
assertFalse(bill.save(null));
}
Generally, implementation of read() and store() involves integrating with external system such as database, file system. This makes the test go hand in hand with the external system.
#Test
public void insertsBillToDatabase() {
//setup your database
bill.store(aBill);
//fetch the inserted bill then assert
}
These tests are focused on whether you component is making an correct abstration on the external system.
Tests depending on external system are expensive because they are relatively slow and difficult to setup/cleanup. You'd better seperate business conerns and integration concerns if there are some complex business logic in the store().
public void store(Bill bill) {
//business logic
billDao.save(bill); // delegate to an injected dao, you can replace it with a test double in test code
}
#Test
public void doesSthToBillBeforeSave() {
//replace your billDao with a stub or mock
bill.store(aBill);
//assert the billDao stub / mock are correctly invoked
//assert bill's state
}