Mock a static method multiple times using JMockit within a JUnit test - java

I have a class with static methods that I'm currently mocking with JMockit. Say it looks something like:
public class Foo {
public static FooValue getValue(Object something) {
...
}
public static enum FooValue { X, Y, Z, ...; }
}
I have another class (let's call it MyClass) that calls Foo's static method; I'm trying to write test cases for this class. My JUnit test, using JMockit, looks something like this:
public class MyClassTest extends TestCase {
#NonStrict private final Foo mock = null;
#Test public void testMyClass() {
new Expectations() {
{
Foo.getValue((Object) any); result = Foo.FooValue.X;
}
};
}
myClass.doSomething();
}
This works fine and dandy, and when the test is executed my instance of MyClass will correctly get the enum value of Foo.FooValue.X when it calls Foo.getValue().
Now, I'm trying to iterate over all the values in the enumeration, and repeatedly run the test. If I put the above test code in a for loop and try to set the result of the mocked static method to each enumeration value, that doesn't work. The mocked version of Foo.getValue() always returns Foo.FooValue.X, and never any of the other values as I iterate through the enumeration.
How do I go about mocking the static method multiple times within the single JUnit test? I want to do something like this (but obviously it doesn't work):
public class MyClassTest extends TestCase {
#NonStrict private final Foo mock = null;
#Test public void testMyClass() {
for (final Foo.FooValue val : Foo.FooValue.values() {
new Expectations() {
{
// Here, I'm attempting to redefine the mocked method during each iteration
// of the loop. Apparently, that doesn't work.
Foo.getValue((Object) any); result = val;
}
};
myClass.doSomething();
}
}
}
Any ideas?

Instead of "mocking the method multiple times", you should record multiple consecutive return values in a single recording:
public class MyClassTest extends TestCase
{
#Test
public void testMyClass(#Mocked Foo anyFoo)
{
new Expectations() {{
Foo.getValue(any);
result = Foo.FooValue.values();
}};
for (Foo.FooValue val : Foo.FooValue.values() {
myClass.doSomething();
}
}
}
It could also be done with a Delegate, if more flexibility was required.

Related

Unit test with wrapped public static method Java

I am not very familiar with Unit Tests, I know that they are very important for code quality, and I want to write some in my project. I recently run into some issues. The context is that, I am writing the testClassA for my Aclass, but some functions in Aclass depend on BClass.
BClass is a utility function, so it has many public static function.
AClass uses Bclass's functions :
public class Aclass{
public boolean Afunction()
{
String result = Bclass.Bfunction();
//do stuff with result
return true
}
}
public class Bclass{
public static String Bfunction()
{
//function code
}
}
I want that everytime the BClass.Bfunction is called, then I can return what I want without really execute the real Bfunction in Bclass, so my Aclass doesn't depend on other class in my test. Is it possible ?
One approach that limits your changes to just the Aclass, and eliminates the dependency on Bclass (as you asked for) is extract-and-override:
Identify the code you wish to bypass in your test and extract it to a method.
Override that method in a sub-class of your class-under test. In this overidden method, you can code whatever mock behavior is appropriate for the test:
So your modified Aclass would look like this:
public class Aclass {
public boolean Afunction() {
String result = doBfunction();
// do stuff with result
return true;
}
// This is your "extracted" method.
protected doBfunction() {
return Bclass.Bfunction();
}
}
and your test class would look like this:
class AClassTest {
#Test
public void testAFunction() {
Aclass testObject = new TestableAclass();
boolean value = testObject.AFunction();
// now you can assert on the return value
}
class TestableAclass extends Aclass {
#Override
protected String doBfunction() {
// Here you can do whatever you want to simulate this method
return "some string";
}
}
}

Junit test for a method which calls another void method of another component

I have a method A (Check) on which it calls another void method B(wantToSkip). A will throw one exception for which I am going to write junit test. In this case want to avoid calling method B. How can I achieve that?
Code is as below:
class A {
Class c = new Class();
Public void setC(C c) {
this.c = c;
}
String check(){
try{
//do something
} catch(Exception test) {
c.wantToSkip();
}
...
}
}
Here I just want to make sure exception test is thrown but want to skip calling method inside it.
I tried following but did not work
#Test//(expected= Exception.class)
public void test(){
class c = Mockito.spy(new class());
Mockito.doNothing().when(c).wantToSkip();
check(some arguments);
}
If you provide a setter for Class c, you can use Mockito to achieve what you want to do.
Your unit test would look something like this:
#Mock private Class mockC;
#Test
public void test(){
A a = new A();
a.setC(mockC);
a.check(some arguments);
}
Alternatively you could take your Class c in the constructor, in which case your test could look like this.
#Mock private Class mockC;
#Test
public void test(){
A a = new A(mockC);
a.check(some arguments);
}
The mockC has no behaviour specified for when c.wantToSkip() is called, so it won't do anything.
The latest non-beta version for mockito is here: http://mvnrepository.com/artifact/org.mockito/mockito-all/1.10.19

How to replace method invocation with mock?

I have a class with two methods. I want to replace invocation of second method with expected result.
Here is my class under test
public class A {
public int methodOne() {
return methodTwo(1);
}
public int methodTwo(int param) {
// corresponding logic replaced for demo
throw new RuntimeException("Wrong invocation!");
}
}
And test
public class ATest {
#Test
public void test() {
final A a = spy(new A());
when(a.methodTwo(anyInt())).thenReturn(10);
a.methodOne();
verify(a, times(1)).methodTwo(anyInt());
}
}
Why I'm get an exception when start the test?
Two things that will help you here. First, from the documentation it seems you need to use the do*() api with spy() objects. Second, to call the "real" method you need to declare it specifically using doCallRealMethod()
Here's the updated test that should work for you:
public class ATest {
#Test
public void test() {
final A a = spy(new A());
doReturn(10).when(a).methodTwo(anyInt());
doCallRealMethod().when(a).methodOne();
a.methodOne();
verify(a, times(1)).methodTwo(anyInt());
}
}

Mocking a call on a public method of an abstract class without subclassing the abstract Class, using mockito prefererably

I am writing an unit testing using JUNIT + Mockito to test a method like :
public someObject methodUnderTest(){
SomeObject obj = SomeAbstractClass.someMethod();
if(obj!=null){
obj.someOtherMethod();
}
return someThing;
}
And I would like to mock the call on abstract Class "SomeAbstractClass" mentioned in above code fragment so i can verify call on "obj" like :
verify(SomeAbstractClass).someMethod();
verify(obj).someOtherMethod();
I have tried using mockito features like :
Mockito.CALLS_REAL_METHODS
Mockito.RETURNS_MOCKS
but they don't work due to dependencies not available to the SomeAbstractClass.
Note:
1) SomeObject is an Interface.
2) I need a technique to test above code fragment. I am constrained to use the above code fragment and cannot change the code fragment.
You can use PowerMock to mock static and final methods.
It sounds like the problem is that your use of CALLS_REAL_METHODS is applying to the entire class, where you really want to mock out specific methods (i.e. make a "partial mock"). You have two options here, one using thenCallRealMethod, and one using CALLS_REAL_METHODS and then specifically mocking the calls you need:
public void testMethodUnderTest_mockSpecificThings() {
SomeAbstractClass myAbstractClass = Mockito.mock(SomeAbstractClass.class);
SomeAbstractClass myObject = Mockito.mock(SomeObject.class);
when(myAbstractClass.someMethod()).thenReturn(foo);
when(myAbstractClass.methodUnderTest()).thenCallRealMethod();
myAbstractClass.methodUnderTest();
verify(myAbstractClass).someMethod();
verify(myObject).someOtherMethod();
}
public void testMethodUnderTest_makeSpecificRealCalls() {
SomeAbstractClass myAbstractClass =
Mockito.mock(SomeAbstractClass.class, CALLS_REAL_METHODS);
SomeAbstractClass myObject = Mockito.mock(SomeObject.class);
// overrides the default answer
when(myAbstractClass.someMethod()).thenReturn(myObject);
myAbstractClass.methodUnderTest();
verify(myAbstractClass).someMethod();
verify(myObject).someOtherMethod();
}
Be forewarned that SomeAbstractClass is never actually instantiated, so if you rely on any behavior in the abstract class constructor, like variable initialization--including inline initialization where the fields are declared--you will need to make those calls explicitly yourself.
Assumption: if you write unit test, I guess you still can modify tested method a bit.
Solution:
extract static method call to overridable method:
public someObject methodUnderTest() {
SomeObject obj = getSomeObject();
if(obj!=null){
obj.someOtherMethod();
}
return someThing;
}
protected SomeObject getSomeObject() {
return SomeAbstractClass.someMethod();
}
then you can use Mockito Spy to partially mock the object you actually test:
private ClassUnderTest classUnderTest;
#Before
public void setUp() {
classUnderTest= new ClassUnderTest();
classUnderTest = Mockito.spy(classUnderTest);
}
#Test
public void test() {
SomeObject someObject = Mockito.mock(SomeObject.class);
when(classUnderTest.getSomeObject()).thenReturn(someObject);
classUnderTest.methodUnderTest();
verify(someObject).someOtherMethod();
}
#Test
public void testNull() {
when(classUnderTest.getSomeObject()).thenReturn(null);
classUnderTest.methodUnderTest();
verify(something);
}
Use anonymous classes:
public interface SomeObject {
public Object someOtherMethod();
}
public abstract class SomeAbstractClass {
abstract SomeObject someMethod();
}
#Test
public void test() {
SomeAbstractClass target = new SomeAbstractClass() {
SomeObject someMethod() {
// some impl
SomeObject someObject = new SomeObject() {
public Object someOtherMethod() {
// some other impl
}
};
return someObject;
}
};
// now test target
}

java.lang.IllegalStateException: missing behavior definition for the preceding method call getMessage("title")

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.

Categories