I am having a hard time getting this one piece of mocking figured out for my unit tests. The classes in question are all part of legacy code that I don't really have the option of changing right now (I am hoping to be able to do some refactoring in the future, but need tests now).
Here are the two classes that I am dealing with, and the specific part I am having trouble with. Class A declares an object using new and then class B uses the object. I am trying to mock the object but I keep getting the real version of it instead of the mocked version.
public class B extends A(){
...
int x = problemObj.doMethod();
}
public class A(){
...
ProblemObj problemObj = new ProblemObj();
}
Here is my test class.
#RunWith(PowerMockRunner.class)
#PrepareForTest({A.class, B.class})
public class ATest(){
private ProblemObj problemObjMock;
#Before
public void setUp(){
problemObj = PowerMockito.Mock(ProblemObj.class);
}
#Test
public void test(){
PowerMockito.whenNew(ProblemObj.class).withNoArguments().thenReturn(problemObj);
...//rest of test below here
}
}
I have done other whenNew mocking in tests and set it up the same way as this. But for some reason this object being in the superclass is really throwing me off.
Versions used are Junit:4.11, Mockito:1.9.5, Powermock: 1.6.6
Related
I Have a class for which i want to write a Junit unit test case.
public class ComparatorUtil {
public static Map<String, ValueDifference<Object>> compareJsonObject(Object srcObject, Object targetObject)
throws JsonGenerationException, JsonMappingException, IOException {
String initialJson = ConverterUtil.convertObjectToJson(srcObject);
String updatedJson = ConverterUtil.convertObjectToJson(targetObject);
Gson g = new Gson();
Type mapType = new TypeToken<Map<String, Object>>(){}.getType();
Map<String, Object> firstMap = g.fromJson(initialJson, mapType);
Map<String, Object> secondMap = g.fromJson(updatedJson, mapType);
Map<String, MapDifference.ValueDifference<Object>> diffMap = Maps.difference(firstMap, secondMap).entriesDiffering();
return diffMap;
}
}
public class ConverterUtil {
public static String convertObjectToJson(Object o)
throws JsonGenerationException, JsonMappingException, IOException {
ObjectMapper mapperObj = new ObjectMapper();
return mapperObj.writeValueAsString(o);
}
}
Junit test case written by me:-
#RunWith(PowerMockRunner.class)
#PrepareForTest(ConverterUtil.class)
public class ComparatorUtilTest {
#Before
public void setUp() {
PowerMockito.mockStatic(ConverterUtil.class);
}
#Test
public void testValueDiff() throws JsonGenerationException, JsonMappingException, IOException {
TestObject srcObject = new TestObject();
srcObject.setColor("white");
srcObject.setId(1);
TestObject targetObj = new TestObject();
targetObj.setColor("white");
targetObj.setId(1);
targetObj.setSuffix("AA");
ComparatorUtil.compareJsonObject(srcObject, targetObj);
PowerMockito.verifyStatic(VerificationModeFactory.times(2));
ConverterUtil.convertObjectToJson(srcObject);
ConverterUtil.convertObjectToJson(targetObj);
}
}
When I am running the test class, I am getting a Null Pointer Exception as the initialJson and updatedJson is coming to be null. Can anyone please tell me where am I doing wrong?
So many things so wrong here.
You seem to assume how to use PowerMock. But what you put together simply doesn't make sense! You need to create a mocking specification using 'when().thenReturn()' for example.
Meaning: it is not enough to instruct PowerMock that a certain class will be mocked. You have to tell PowerMock about the actual values to be returned when these static methods are invoked.
so start by reading a good tutorial top to bottom. Don't use PowerMock for your own code, instead look how a tutorial solves a simple problem.
Then: PowerMock comes at certain cost. So you avoid using it. You rather should step back and look into reworking your code so that it can be tested without the need to mock static methods. You see, we are talking about code that transforms some input into some output. You should be able to write production and test code that requires no mocking at all for such situations. If at all, you should use frameworks such as Mockito - good production code can be tested without PowerMock.
More specifically: why is there a need to mock the static method? That seems to indicate that your ObjectMapper doesn't work in your unit test setup. It starts right there!
You see, a good unit test for your conversion method should simply look like:
assertThat(someConverterUnderTest.convert(fineTunedInput), is(expectedOutput));
That's it! You should design your converter to fully work in your unit test environment. And then all need for mocks is gone. In other words: you are currently testing implementation details. Instead you should always try testing the public contract of your methods. Testing implementation details is sometimes unavoidable, but as written before: the code you are showing here should really really be tested without mocks.
Then: even when you need mocks: the static methods are getting in your way. That is a clear signal that you shouldn't be using static here! Instead, you turn those elements that might require mocking either into parameters or into fields of your classes under test. Because then you can simply inject mocked objects. Which means that you don't need the PowerMock(ito) tooling anymore.
I want to test SomeClass methods.
For that, I need SomeClass instance in every test so I'm using #Before annotation and initiate an instance of SomeClass named SC.
The problem is:- How can I test the constructor function after I already use it? It doesn't make sense.
Additional question:- The constructor can get number of arguments and they can influnce the methods outputs, should I mock this class instead of creating an instance of it?
public class SomeClassTest {
SomeClass SC;
#Before
public void initlize() throws IOException{
SC= new SomeClass (argument1,argument2,..);
}
#Test
public void ConstructorTest() {
}
Just don't use the object SC in your ConstructorTest. If you wan't to test a certain outcome from the construction of a SomeClass object with certain parameters then just construct it as such within your ConstructorTest and then assert the relevant outcomes you expect on the newly constructed object.
And no you shouldn't be mocking this class. The test is for testing this class so if you mock it's behaviour then you aren't really testing anything.
public static ResponseBean call(Bean bean) throws Exception {
// statements...
IgnoreCall.ignoreMethodCall(bean);
// statements...
// return
}
With the code snippet above, is it possible to test the method ignoring invocation of IgnoreCall.ignoreMethod(Bean) without needing to place the entire statement under a boolean condition?
Here's the unit test code snippet:
#RunWith(PowerMockRunner.class)
#PrepareTest
public ClassHelperTest {
#Test
public void testCall() throws Excpetion {
// stubbing...
ResponseBean responseBean = ClassHelper.call(bean);
// verify/ies
// assert/s
}
}
Notes:
Refactoring ClassHelper.call(Bean) should be avoided. Even with a bad OO design, refactoring is costly.
Method signature is locked unless another pattern is applicable for replacement.
Tried using Mockito.when and PowerMockito.when on the target static method, stubbing didn't work on run-time debug.
As your comments indicate that changing your production code is not possible, you "simply" have to dive into the static-mocking aspects of PowerMock; as outlined here for example.
Basically you need to enable IgnoreCall for static mocking; and then you make calls to ignoreMethodCall() a no-op.
But as you keep asking: the core problem with your question is the fact that you want to mock out a static method that is void. I have a complete example below, but before that some explanations.
The point is: you call a method for two reasons:
It has a side effect
It returns a value, and maybe, causes a side effect, too
A void method can only be called for side effects. And the thing is: when you do static mocking, then that works on class level.
Meaning: you instruct PowerMock to "prevent" any of the static methods of some class from execution; you simply "erase" the side effects of all those static methods! So, by telling PowerMock to do those static mocks, all void methods are already "gone".
But as said, you might also call methods for their return value. And then is when the when() method of Mockito kicks in. You use that method to say: when that value-returning method is invoked, then do this or that.
Long story short; here is a [mcve] using the elements you asked for:
package ghostcat.test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
class IgnoreCall {
public static void ignoreMethodCall(Object o) {
System.out.println("SHOULD NOT SHOW UP: " + o);
}
}
class CuT {
public static Object call(Object bean) {
System.out.println("statement1");
IgnoreCall.ignoreMethodCall(bean);
System.out.println("statement2");
return "whatever";
}
}
#RunWith(PowerMockRunner.class)
#PrepareForTest(IgnoreCall.class)
public class PMTest {
#Test
public void test() {
PowerMockito.mockStatic(IgnoreCall.class);
CuT.call("yeha");
}
}
As in your example ... there is IgnoreCall; used within that a static method that I just called "call".
This prints:
statement1
statement2
When I go in and comment out
// PowerMockito.mockStatic(IgnoreCall.class);
It prints:
statement1
SHOULD NOT SHOW UP: yeha
statement2
So, a simple example that should tell you exactly what you need to do.
I worked with eclipse neon, IBM java8 JDK, and simply imported all the JARs from powermock-mockito-junit-1.6.6.zip into my test project.
Is there an easy way, using Mockito, to load a mock class when another is requested OR to override the test ClassLoader?
Basically I have a class Foo that has a member "ClassA" in it. I want to replace to use "TestClassA" instead of "ClassA" during testing. I don't want to use dependency injection because it doesn't make any sense for actual operation. (It can never be anything other than ClassA)
Can I do this?
It can never be anything other than ClassA
...except that it is, in your test. Test code is real code, and though that doesn't mean it should sneak into your production application, it does mean that you need to write in the flexibility you need for all of its use cases, and that includes testing.
Mockito works via subclasses: A mockFoo created by mock(Foo.class) or #Mock Foo mockFoo is actually a proxy subclass Mockito created that overrides each of Foo's methods. As you can tell from that description, Mockito thus cannot change the behavior of every Foo object and especially cannot change the type of the object returned from new Foo().
You have two options, that I can see:
Accept a ClassA or InterfaceA instance in one of your constructors. If you put your tests in the same Java package as your class under test (even in a different source tree), you can even make the constructor package-private, or keep it private and create a static factory method like createForTest(ClassA).
Example:
public class ConsumerToTest {
private final ClassA classA;
/** For public use. */
public ConsumerToTest() {
this(new ClassA());
}
/** For use in tests. */
ConsumerToTest(ClassA class) {
this.classA = classA;
}
// ...
}
Use PowerMock, which has a Mockito integration known as PowerMockito. Though Mockito uses pure proxy subclasses and code generation, PowerMockito actually rewrites the bytecode of the system-under-test. This means that you can mock static methods and constructors that Mockito couldn't adjust on its own through polymorphism.
Personally, I very much prefer solution 1: The code is yours to control, and as long as you're clear that your test is a first-class consumer of your system-under-test, you're free to design it to be testable in the first place.
Doing it by constructor is what I prefer.
For example
public class Foo {
private ClassA classA;
public Foo(ClassA classA) {
this.classA = classA;
}
}
public class FooTest {
private Foo foo;
#before
public void setup() {
foo = new Foo(Mockito.mock(ClassA.class);
}
}
It's really simple to do this using Mockito.
public class Foo {
private ClassA classA;
}
Test will look like this:
#RunWith(MockitoJUnitRunner.class)
public class FooTest {
#Mock
private ClassA classA;
#InjectMocks
private Foo foo = new Foo();
//Test methods
}
That's it, you have mocked ClassA!
Hi I am new to unit testing. Is it possible to access methods that are private?
A very simple example
ObjectA
----------
File file;
private void setupFile (){
//do something
file = "C:\file.dat"
}
In TestCase
File sth = ObjectA.setupFile();
assertNotNull(sth);
I am unable to test whether the file variable is null in method ObjectA.setup()
as I cannot run ObjectA.setupFile()
I am not sure about whether doing like this make sense in terms of unit testing.
So is that a better practice to write every method returning sth and set them public for easier unit testing?
Thanks in advance
In general, you should avoid changing the access of a method/field to enable testing. If you do this then you risk developers using the method directly.
However, if you do need to, then making it protected as Deco says is a good way, so it's accessible from the JUnit tests. If you do this, make sure that it is well documented that this is an method for internal use.
A better way is to test the behaviour of the public methods; you shouldn't care about internal implementation details of a class, so you should only be testing public methods. It's hard to tell from your code, but presumably, the setupFile() has effects later on other methods, so you can test those effects, not the fact that file is not null.
External dependencies (such as dependencies on file system, environment variables) can be worked around in your tests, or injected directly into the class. For the general principle, see my answer to How to test code dependent on environment variables using JUnit?
If it is not absolutely necessary to have the method as private, you can have it as package private (i.e. default access) so that you can call it directly in a JUnit test.
Package private methods can only be used in the package that they are declared, and do not become part of the API of the class. You declare a method package private by putting no modifier on it's declaration.
Here's an example to demonstrate:
public class MyClass() {
int foo;
public MyClass() {
this.foo = 0;
}
void notSoComplexCalculationMethod(int a) {
foo = a * 2;
}
//Other methods here . . .
}
public class MyClassTest extends TestCase {
private MyClass myClass;
protected void setUp() {
super.setUp();
myClass = new MyClass();
}
public void testNotSoComplexCalculationMethod() {
int a = 2;
assertEquals(4, myClass.notSoComplexCalculationMethod(a));
//Unit test passes, yay! Now you've tested a package private method.
}
}