[10/7/06 4:00 Edited example code]
I'm trying to test some code (using JMockIt with TestNG) without touching the database, but it appears a mocked method is still actually called. Here's the simplified setup:
class DBRow {
public DBRow() { }
public DBRow(Object obj) {
initialize(obj);
}
public void insert() {
actuallyAddRowToDatabase();
}
}
class MyObject extends DBRow {
MyObject(Object obj) {
super(obj);
}
public void insert(Object obj) {
doSomething(obj);
insert();
}
}
class Factory {
static MyObject createObject(Object obj1, Object obj2) {
MyObject newObj = new MyObject(obj1);
newObj.insert(obj2);
return newObj;
}
}
I wanted to mock the insert operation to prevent an insertion in the actual database, so I tried something like this:
#Test
public void testCreation() {
new Expectations(MyObject.class) {
MyObject mock = new MyObject(null) {
#Mock
public void insert(Object obj) { }
};
{
new MyObject(anyString); result = mock;
}};
MyObject test = Factory.createObject("something", "something else");
}
But it appears that the real insert(Object) is still being called. I'm specifying that the class is mocked so all instances should be mocked, right? And I'm specifying that the insert method should be mocked, so why would the real method be getting called?
There's also a second problem with the above. When I define the mock class inside the Expectations block (as above), it seems that only the Row() constructor is being called instead of Row(Object), and thus the object is not correctly initialized. I fixed this by moving it into a #BeforeTest method and instantiating the class there. Here's what that looks like:
private MyObject mock;
#BeforeTest
public void beforeTest() {
new MockUp<MyObject>() {
#Mock
public void insert(Object obj) { }
};
mock = new MyObject("something");
}
#Test
public void testCreation() {
new Expectations(MyObject.class) {{
new MyObject(anyString); result = mock;
}};
MyObject test = Factory.createObject("something", "something else");
}
So this seems to get the correct constructor to be called, but it still seems that insert() is being called as well. Any insights?
You are not using mocked object to call your fucntion i.e. private MyObject mock; but a real object test,
MyObject test = new MyObject("something", "something else");
Call testStuff() on mockinstead of test.
All instances wouldn't be automatically mocked, you have to work with mocked instances.
I was finally able to write my tests such that the right constructor got called and no actual database operation occurred. I think part of the problem I was bumping into was that one of the methods in the Expectations block was getting a different object than I expected for a parameter I wasn't interested in. And I think the other part of my problem was mixing up the roles of a MockUp class and Expectations recordings.
The code under test didn't change. Here's my simplified example again for convenience:
class DBRow {
public DBRow() { }
public DBRow(Object obj) {
initialize(obj);
}
public void insert() {
actuallyAddRowToDatabase();
}
}
class MyObject extends DBRow {
MyObject(Object obj) {
super(obj);
}
public void insert(Object obj) {
doSomething(obj);
insert();
}
}
class Factory {
static MyObject createObject(Object obj1, Object obj2) {
MyObject newObj = new MyObject(obj1);
newObj.insert(obj2);
return newObj;
}
}
Here's essentially what I ultimately ended up with for test code:
Object something;
Object somethingElse;
#BeforeTest
public void beforeTest() {
new MockUp<MyObject>() {
#Mock
public void insert() { } // override the "actual" DB insert
}; // of Row.insert()
}
#Test
public void testCreation() {
MyObject mock = new MyObject(something); // object correctly init'd
// by Row.initialize(Object)
new Expectations(MyObject.class) {{
new MyObject(something); result = mock;
mock.insert(somethingElse);
}};
MyObject test = Factory.createObject(something, somethingElse);
}
The key points were that A) I created a MockUp class to override the DB operations, and B) created a local instance of that partially mocked instance to record my Expectations.
Related
I am trying to write a test for pre-existing class.
class ClassToBeTested {
private final Obj1 a;
ClassToBeTested(String anotherVariable) {
a = new Obj1(anotherVariable);
}
public void methodToBeTested() {
if(invokeSomeOtherMethod()) {
a.getAnotherVariable().doSomething();
}
}
public boolean invokeSomeOtherMethod() {
// return true or false based on some logic
}
Obj1 getObj1() {
return a;
}
}
Below is my Test Class:
class TestClass {
#Test
public void testMethod() {
ClassToBeTested x = new ClassToBeTested("someString");
ClassToBeTested spyX = spy(x);
doReturn(false).when(spyX).invokeSomeOtherMethod();
spyX.methodToBeTested();
verify(spyX, times(1)).getObj1().doSomething();
}
}
This is my understanding:
Since the obj1 is private final object which is created in the class constructor, it neither be directly accessed in the test method nor force the spyObject to use a mocked version of obj1.
Also since verify() requires mocked version of obj1, it throws me an error:
Wanted But Not invoked: x.getObj1(), however there are otherInteractions with this mock: x.invokeSomeOtherMethod()
Is my understanding wrong? What would be the way to test testMoethod()?
You seem to not understand how to do proper dependency injection. You don't need to change all your code in order to make it easier to test - just use constructor telescoping for example:
class ClassToBeTested {
private final Obj1 a;
public ClassToBeTested(String anotherVariable) {
this(new Obj1(anotherVariable));
}
ClassToBeTested(Obj1 a) {
this.a = a;
}
Done. Now you have a package-protected constructor that you can use to insert an instance of a directly. And all your other production code can stay like it is.
In other words: don't "fix" your design problems by using mocking framework tricks.
Version of JMockit that was used: 1.21
I have interface like this.
TestInterface:
public interface TestInterface {
boolean callMethod();
}
A TestClass have field is a instance of that interface
TestClass:
public class TestClass {
private final TestInterface inner = new TestInterface() {
#Override
public boolean callMethod() {
subMethod();
return false;
}
};
public void subMethod() { System.out.println("Sub method");
};
}
I try to verify calling method by fake an interfacein this tutorial.
http://jmockit.org/tutorial/Faking.html#interfacesd
Test method.
public class TestInterfaceTest {
TestClass sut;
#Before
public void setUp() {
sut = Deencapsulation.newInstance(TestClass.class);
}
#Test
public void mockAllClassesImplementingAnInterface() {
TestInterface testInterface = new MockUp<TestInterface>() {
#Mock
public boolean callMethod(Invocation inv) {
inv.proceed(); // throw exception here -> Will my expected method be called here?
return true;
}
}.getMockInstance();
Deencapsulation.setField(sut, "INTER", testInterface);
new NonStrictExpectations() {
{
Deencapsulation.invoke(sut, "subMethod");
}
};
Boolean result = Deencapsulation.invoke(Deencapsulation.getField(sut, "INTER"), "callMethod");
assertTrue(result);
new Verifications() {
{
Deencapsulation.invoke(sut, "subMethod"); times = 1;
}
};
}
}
java.lang.IllegalArgumentException: No class with name
"ndroid.examples.helloandroid.$Impl_TestInterface" found
If you guys don't mind, could you please tell me how to resolve this byg. Many thanks.
Your problem, in my reevaluation of this issue, would seem to lie in the line inv.proceed(). You can't have that line in a Mockup of an interface.
Invocation.proceed() is intended when you want the MockUp implementation to proceed into the real code. But because you are mocking up an interface, there is no real code. You may think there is because your implementation of TestClass has an anonymous implementation of the interface, but the MockUp knows nothing of that anonymous class; it's doing a mockup of the interface and not of your anonymous implementation.
If you get rid of that line, the call to Invocation.proceed(), I think you'll find your error goes away.
Based on the guidance of #dcsohl. The code below works for me.
#Test
public void mockAllClassesImplementingAnInterface() {
// Partial mocking
new NonStrictExpectations(sut) {
{
sut.subMethod();
}
};
// Actual invocation
Deencapsulation.invoke(Deencapsulation.getField(sut, "inner"), "callMethod");
// Verify
new Verifications() {
{
Deencapsulation.invoke(sut, "subMethod");
times = 1;
}
};
}
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());
}
}
I'd like to avoid mocking the getClass() method for a class but cannot seem to find any way around it. I'm trying to test a class that stores objects class types in a HashMap to a particular method to be used later. A brief example of this is:
public class ClassToTest {
/** Map that will be populated with objects during constructor */
private Map<Class<?>, Method> map = new HashMap<Class<?>, Method>();
ClassToTest() {
/* Loop through methods in ClassToTest and if they return a boolean and
take in an InterfaceA parameter then add them to map */
}
public void testMethod(InterfaceA obj) {
final Method method = map.get(obj.getClass());
boolean ok;
if (method != null) {
ok = (Boolean) method.invoke(this, obj);
}
if (ok) {
obj.run();
}
}
public boolean isSafeClassA(final ClassA obj) {
// Work out if safe to run and then return true/false
}
public boolean isSafeClassB(final ClassB obj) {
// Work out if safe to run and then return true/fals
}
}
public interface InterfaceA {
void run()
}
public class ClassA implements InterfaceA {
public void run() {
// implements method here
}
}
public class ClassB implements InterfaceA {
public void run() {
// implements method here
}
}
I then have a JUnit test that looks a little like this:
#RunWith(PowerMockRunner.class)
#PrepareForTest({ClassA.class})
public class ClassToTestTest {
private final ClassToTest tester = new ClassToTest();
#Test
public void test() {
MockGateway.MOCK_GET_CLASS_METHOD = true;
final ClassA classA = spy(new ClassA());
doReturn(ClassA.class).when(classA).getClass();
MockGateway.MOCK_GET_CLASS_METHOD = false;
tester.testMethod(classA);
verify(classA).run();
}
}
My problem is although inside the test() method classA.getClass(); will return ClassA, once inside tester's testMethod() method it still returns the ClassA$EnhancerByMockitoWithCGLIB$... class and so my object useful will always be null.
Is there any way I can get around mocking the class or what do I need to do to fix this?
Thanks in advance.
Your problem is actually that getClass is final in Object, so you can't stub it with Mockito. I can't think of a good way around this. There is one possibility, that you might consider.
Write a utility class that has a single method
public Class getClass(Object o){
return o.getClass();
}
and refactor the class that you're testing, so that it uses an object of this utility class, instead of calling getClass() directly. Then, make it possible to inject the utility object, either with a special package-private constructor, or with a setter method.
public class ClassToTest{
private UtilityWithGetClass utility;
private Map<Class<?>, Object> map = new HashMap<Class<?>, Object>();
public ClassToTest() {
this(new UtilityWithGetClass());
}
ClassToTest(UtilityWithGetClass utility){
this.utility = utility;
// Populate map here
}
// more stuff here
}
Now, in your test, make a mock of the object and stub getClass. Inject the mock into the class that you're testing.
Wow, what a headache to get this code testable. The main issues are that you can't use mock objects as key objects into your calls to map.get(obj.getClass()), and you're trying to invoke() potentially mock objects for your testing. I had to refactor your class under test so that we can mock out the functionality/behaviour and be able to verify its behaviour.
So this is your new implementation to be tested with member variables decoupling the various pieces of functionailty and injected by the test class
public class ClassToTest {
MethodStore methodStore;
MethodInvoker methodInvoker;
ClassToInvoke classToInvoke;
ObjectRunner objectRunner;
public void testMethod(InterfaceA obj) throws Exception {
Method method = methodStore.getMethod(obj);
boolean ok = false;
if (method != null) {
ok = methodInvoker.invoke(method, classToInvoke, obj);
}
if (ok) {
objectRunner.run(obj);
}
}
public void setMethodStore(MethodStore methodStore) {
this.methodStore = methodStore;
}
public void setMethodInvoker(MethodInvoker methodInvoker) {
this.methodInvoker = methodInvoker;
}
public void setObjectRunner(ObjectRunner objectRunner) {
this.objectRunner = objectRunner;
}
public void setClassToInvoke(ClassToInvoke classToInvoke) {
this.classToInvoke = classToInvoke;
}
}
This is your test class that no longer requires PowerMock, because it can't mock the Method class. It just returns a NullPointerException.
public class MyTest {
#Test
public void test() throws Exception {
ClassToTest classToTest = new ClassToTest();
ClassA inputA = new ClassA();
// trying to use powermock here just returns a NullPointerException
// final Method mockMethod = PowerMockito.mock(Method.class);
Method mockMethod = (new ClassToInvoke()).getClass().getMethod("someMethod"); // a real Method instance
// regular mockito for mocking behaviour
ClassToInvoke mockClassToInvoke = mock(ClassToInvoke.class);
classToTest.setClassToInvoke(mockClassToInvoke);
MethodStore mockMethodStore = mock(MethodStore.class);
classToTest.setMethodStore(mockMethodStore);
when(mockMethodStore.getMethod(inputA)).thenReturn(mockMethod);
MethodInvoker mockMethodInvoker = mock(MethodInvoker.class);
classToTest.setMethodInvoker(mockMethodInvoker);
when(mockMethodInvoker.invoke(mockMethod,mockClassToInvoke, inputA)).thenReturn(Boolean.TRUE);
ObjectRunner mockObjectRunner = mock(ObjectRunner.class);
classToTest.setObjectRunner(mockObjectRunner);
// execute test method
classToTest.testMethod(inputA);
verify(mockObjectRunner).run(inputA);
}
}
The additional classes you require are as follows
public class ClassToInvoke {
public void someMethod() {};
}
public class ClassA implements InterfaceA {
#Override
public void run() {
// do something
}
}
public class ClassToInvoke {
public void someMethod() {};
}
public class MethodInvoker {
public Boolean invoke(Method method, Object obj, InterfaceA a) throws Exception {
return (Boolean) method.invoke(obj, a);
}
}
public class MethodStore {
Map<Class<?>, Method> map = new HashMap<Class<?>, Method>();
public Method getMethod(InterfaceA obj) {
return map.get(obj);
}
}
Put all this into your IDE and it will pass with a Green bar...woohoo!
I've faced with similar question, too. I think you should add ClassToTest.class to #PrepareForTest, because you want to mock the getClass() function in that class
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
}