I want to mock private static inner class using Powermock (based on EasyMock). This does not come from production code, it's just a question whether something is possible. I am pretty sure this is bad design, but it's something I'm trying for science.
Let's say we have a class with static private inner class:
public class Final {
private static class Inner {
private final int method () { return 5; }
}
public int callInnerClassMethod () {
return new Inner().method();
}
}
I would like to mock the Inner class and its method.
I have come out with the code as follows:
Class<?> innerType = Whitebox.getInnerClassType(Final.class, "Inner");
Object innerTypeMock = PowerMock.createMock(innerType);
PowerMock.expectNew(innerType).andReturn(innerType);
PowerMock.expectPrivate(innerType, "method").andReturn(42);
PowerMock.replay(innerTypeMock);
new Final().callInnerClassMethod();
In the code: we get the type of Inner.class and mock it, when a user creates new object of type Inner we say that we return our instance, and when someone calls its method we provide our implementation for it.
Generally, I am learning about mocking and one can be sure this code proves I don't know what I'm doing. The code does not even compile and I get the following error on the line PowerMock.expectNew(innerType).andReturn(innerType):
andReturn (capture) in IExpectationSetters cannot be applied to
(java.lang.Object)
Is the mocking of private static inner class even possible? I have not found a definitive code example on SO.
I have managed to get around the compile error by using bare Class innerType = ... instead of Class<?> innerType = ... in my code. It feels wrong, but works. I'd grateful if someone explained the difference and how to make it work in the original example. There were also some places where I mixed innerType and innerTypeMock. The full, working test code looks as follows:
Class innerType = Whitebox.getInnerClassType(Final.class, "Inner");
Object innerTypeMock = PowerMock.createMock(innerType);
PowerMock.expectNew(innerType).andReturn(innerTypeMock);
PowerMock.expectPrivate(innerTypeMock, "method").andReturn(42);
PowerMock.replayAll();
System.out.println(""+new Final().callInnerClassMethod());
Related
In Java, I have a class like for example
public class A {
private final Map<Integer, String> steps = ImmutableMap.of(
1, "one"
);
public String getStepOne() {
return steps.get(1);
}
}
Now I need to somehow mock this global variable in a unit test. Unfortunately, I was told to avoid any changes in source code of the tested class for testing purposes, especially, simply providing a getter wouldn't be a satisfying solution.
My attempt was to mock the static method call like
#RunWith(PowerMockRunner.class)
#PrepareForTest({A.class, ImmutableMap.class})
public class ATest {
private A subj = new A();
#Before
public void setUp() {
PowerMockito.mockStatic(ImmutableMap.class);
ImmutableMap<Object, Object> mockedMap = ImmutableMap.of(1, "NEW ONE");
BDDMockito.given(ImmutableMap.of()).willReturn(mockedMap);
}
#Test
public void testGetStepOne() {
System.out.println(subj.getStepOne());
}
}
But this doesn't work, it prints "one" and not "NEW ONE". I suspect that mocking static method calls this way isn't possible if they are called from the initialization of a global variable ... does somebody know if there is any way to mock this variable (as I said, without changes in class A)?
============ EDIT ==================
Well, I agree that generally it does not make much sense to mock an immutable map, but actually, the map looks more like this:
private final Map<Integer, B> steps = ImmutableMap.of(
1, new B()
);
and what I actually need, is to mock the object of type B, which is one of the values, because it is accessed in further methods of the class via steps.get(...).
A pure Java solution might be to use reflection in the #Before method. The trick is to get rid of the final property at first, and then to change the value. See the 1st answer of this: Change private static final field using Java reflection. Same should work for non static members.
See the modified code from this post here: Java reflection example to change final member
I have an abstract class that features no abstract methods... How would one go about testing this? Can I simply import it into a test class and go about business as usual?
Example:
public abstract class SomeAbstractClass implements SomeOtherClass {
// Some variables defined here
private static final String dbUrl = System.getProperty("db.url");
// Some public methods
public String doSomethingToUrl(String url) {
url = url + "/takeMeSomewhereNice";
}
}
Say I pass in an arg for db.url of localhost:8080, and I wanted to test that the doSomethingToUrl method did output the new string... Would it still be in this format?
public class TestUrl {
SomeAbstractClass sac = new SomeAbstractClass();
#Test
public void testUrlChange() throws Exception {
String testUrl = "localhost:8080";
assertThat("localhost:8080/takeMeSomewhereNice",
sac.doSomethingToUrl(testUrl));
}
}
You wouldn't be able to create an instance of just SomeAbstractClass, no - but you could create an anonymous subclass:
private SomeAbstractClass sac = new SomeAbstractClass() {};
You may well want to create a concrete subclass just for the sake of testing though - so that any time you do add abstract methods, you just need to put them there.
While I suspect you could use a mocking framework for this, I suspect it would add more complexity for little benefit, unless you need to check under what situations the abstract methods are called. (Mocks are great for interaction testing, but can be brittle for other purposes.) It could easily make for more confusing error messages (due to the infrastructure involved) as well.
You cannot initialize an abstract class, so your test class wouldn't compile as is.
You can either use an anonymous instance (the example below should suffice):
SomeAbstractClass sac = new SomeAbstractClass(){};
However, I would actually recommend you mock the class by means of a mocking framework such as Mockito or EasyMock.
I want to test a private method in a final utitlity class.
1. The class itself:
The class signature is:
public final class SomeHelper {
/** Preventing class from being instantiated */
private SomeHelper() {
}
And there is the private method itself:
private static String formatValue(BigDecimal value)
The test is allready written, but earlier, the method was in a non-utility non-final class without a private constructor.
The test is using #RunWith(Parameterized.class) already.
Now all I get is an exception:
org.mockito.exceptions.base.MockitoException:
Cannot mock/spy class com.some.package.util.SomeHelper
Mockito cannot mock/spy following:
- final classes
- anonymous classes
- primitive types
2. The test
The most important line in this test is:
String result = Whitebox.invokeMethod(mValue, "formatValue", mGiven);
Is there a way of making the test work?
You don't need to test private methods.
But you SHOULD test the ones that use it. If methods that call your private methods are working as you expect, you can assume private methods are working correctly.
Why?
Nobody will call this method alone, so unit test for it is unnecessary.
You don't need to test private method, because it'll not be called directly. But if it realizes some so complicated logic, you want to do this, you should consider extracting class.
What I finally did is based on the answer from question How do I test a class that has private methods, fields or inner classes? that #Sachin Handiekar provided in a comment.
It's not the most beautiful way, considering that private methods should not be tested, but I wanted it tested and I was just curious.
This is how I did it.
Class someHelper = SomeHelper.class;
Method formatValue = someHelper.getDeclaredMethod("formatValue ", BigDecimal.class);
formatValue.setAccessible(true);
String result = (String) formatValue .invoke(new String(), mGiven);
And it works like a charm.
I have a Spring Controller class which has method defined which accepts private enum as below. How can we write test case for this using Junit/Mockito?
#RequestMapping("/getData")
public String getData(
#RequestParam(value = "someFilter") SomeFilter someFilter)
{
// do something
}
In above code, SomeFilter is an enum which is defined as a private inside class.
When writing test case for above method, as enum is not visible I cannot call the method, i tried of using Mockito.any(), still no use.
Do we have any way to test above method?
So, if the method will be called by spring, then you will have to find out, how and replicate that. But honestly, it still smells like horribly bad code, a public method that isn't actually public...
Anyway, you can of course test it via some reflection magic... Let's assume this simple class...
public class Testy {
private enum TestyEnum {
X,
y;
}
public String someMethod(final TestyEnum testyEnum) {
return testyEnum.name();
}
}
So, we have a private enum and a public method that accepts it as a paramter. To call it, we have to use reflection...
public class TestyTest {
private final Testy toTest = new Testy();
#Test
public void someMethod_should_return_correct_name_of_x() throws Exception {
// Get the class object for our private enum
final Class<?> testyEnumClass = Class.forName( "de.assona.iframe.view.Testy$TestyEnum" );
// List the enum constants
final Object[] consts = testyEnumClass.getEnumConstants();
// Get the method via reflection per name and argument type
final Method method = Testy.class.getMethod( "someMethod", testyEnumClass );
// call (invoke) it...
final Object o = method.invoke( this.toTest, consts[0] );
// And check that the object returned is actually the correct String we expect the name of the private enum constant)
Assert.assertEquals( "X", o );
}
}
But of course, this is a horrible workaround, bad to read, bad to maintain and the solution for a problem you should not have. Spring does not require you to produce bad code, on the contrary, it solves many problems that lead to bad code. So I would really suggest you try to refactor that code to make it testable in a clear, easily maintainable way. Trust me, you (and your fellow codes) will not be happy that you found a way to test bad code, since that makes you keep that bad code. Tested bad code is better than untested bad code, but still bad. You (and your fellow codes) will be much happier in the long run with good code, because it makes everything so much easier...
Instead of calling the method of the controller object, you could test your code with Spring MockMvc.
public class ControllerTest {
private final YourController controller = ...
private final MockMvc mockMvc = MockMvcBuilders.standaloneSetup(controller)
.build();
#Test
public void someTest() throws Exception {
mockMvc.perform(get("/getData").param("someFilter", "THE_NAME_OF_THE_FILTER"))
.andExpect(status().isOk())
.andExpect(content().mimeType("text/html"))
.andExpect(...);
}
}
I have a public class with a private class inside it:
public class Out
{
private class In
{
public String afterLogic;
public In(String parameter)
{
this.afterLogic = parameter+"!";
}
}
}
And wanted to test the In class with jMockit. Something along these lines:
#Test
public void OutInTest()
{
Out outer = new Out();
Object ob = Deencapsulation.newInnerInstance("In", outer); //LINE X
}
The problema is, in LINE X, when trying to cast ob to In, the In class is not recognized.
Any idea how to solve this?
Thanks!
The only constructor in class In takes a String argument. Therefore, you need to pass the argument value:
Object ob = Deencapsulation.newInnerInstance("In", outer, "test");
As suggested in the comment one way is to change the access modifier of the inner class from private to public.
Second way (in case you don't want to make your inner class public), you can test the public method of outer class which is actually calling the inner class methods.
Change the scope of the inner class to default then make sure that the test is in the same package.
There are two approaches, first as mentioned in other posts to change the scope to public. The second which I support is, to avoid testing private class altogether. Since the tests should be written against testable code or methods of the class and not against default behavior.