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.
Related
I need to test private method. What is the correct way of testing below method? I tried using Mockito when.. but how do I mock a private method. I think we cannot Mock private method.
private classObject privateMethod(Message message){
try{
Objectmapper mapper = new ObjectMapper();
return mapper.readValue(message.getBody(), ClassName.class);
}catch(){
throw new Exception();
}
}
//I am getting an exception while testing
byte[] body = {10,-11,12,14,15};
MessageProperties msgProp = new MessageProperties();
Message message = new Message(body, msgProp);
// the above message is passed as parameter to function through
// which private method is called
objectxyz.execute(message);
// execute method
public void execute(Message message){
objectxyz xyz = privateMethod(message);
objectabc abc = service.someMethod(xyz);
List<object> list = someAnotherMethod(abc, xyz);
}
// I tried below code in my test case and have used
// #Mock private ObjectMapper objectMapper;
Mockito.when(objectMapper.readValue(body, ClassName.class)).thenReturn(classObject);
Spring boot has nothing special about it:
Private methods should not be tested - it's an internal "how" of the class and you should mainly test the API of the class - the "capabilities" that it exposes to the user of the class via non-private methods.
Consider treat a class as a black box (with possibly mocked dependencies of this class) and check its functionality as I've explained.
You can use the manifold framework to test with reflection. See this previously answered solution: How do I test a private function or a class that has private methods, fields or inner classes?
These are Basic basic approaches to test private methods.
Don't test private methods.
Give the methods package access.
Use a nested test class.
Use reflection.
Detail article
yup, private method should be a internal method, should use by another public method, so. do not test it;
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 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());
I'm writing some unit tests using JUnit and JMockit and need to write a JMockit MockUp for a method that takes an instance of a private enum as an argument. Here's the the class I need to mock:
public class Result {
//Static constants representing metrics
public static final Metric AVOIDABLE = Metric.avoidable;
public static final Metric UNAVOIDABLE = Metric.unavoidable;
// private enumeration of metric values
private enum Metric {avoidable, unavoidable};
public Long getTodayCount(Metric metric) { //<- instance of private enum
return getValueForKey(metric);
}
}
depending on the specific Metric given I need to return a different Long value. If the Metric enum were public that would be straightforward enough. Something like:
private static class MockResult extends MockUp<Result> {
#Mock
Long getTodayCount(Metric m){ //<-- nope. Metric is private
if(Result.AVOIDABLE.equals(m)){ //<-- can't call equals either
return 1234L;
} else {
return 4567L;
}
}
}
But since Metric is private is there any way to accomplish this aside from changing Metric to be public? That may end up being the only way to accomplish this, but I'm not the author of the Result class and am not completely familiar with the reasoning behind making Metric private in the first place.
As per documentation:
The #Mock annotation marks those methods in the mock-up class which are meant to provide mock implementations for the corresponding methods (of the same signature) in the mocked class.
If the enum is private, you cannot use it in your unit tests as it will not be visible outside the class. Then you cannot define a proper MockUp.
You have to either make Metric class more visible (at least package private) or mock out the whole Result class.
My unit test uses an enum as datapoints (see JUnit Theories).
This enum is only used in the test, therefore I prefer it to be encapsulated and a private nested class. JUnit requires test methods to be public. The test methods have the private enum as argument:
#RunWith(Theories.class)
class ExampleTest {
private enum Lists {
EMPTY,
SINGLE_ELEMENT,
OTHER_ELEMENT,
TWO_ELEMENTS;
public Object createElements() {
// Imagine createElements being abstract and
// implemented in each enum constant.
}
}
#DataPoints
public static final Lists[] ALL_LISTS = Lists.values();
private List<Object> tested;
#Theory
public void add_sizeIncreased(Lists elementsToAdd) {
int oldSize = tested.size();
int nElementsAdded = elementsToAdd.size();
tested.addAll(elementsToAdd);
assertThat(tested.size(), is(equalTo(oldSize + nElementsAdded));
}
}
This rightly causes the warning/hint: "Exporting non-public type through public API" (in Netbeans at least).
What is the correct way to solve this?
I have not found a 'SuppressWarnings'-annotation for it;
The answers to related SO questions Sachin, Aselivanov, and user329820 argue that the warning is correct and that you should make the types public. The unittest differs from these other situations in that the test's public methods are not called by any other code.
(I admit the testframework calls them, but I hope you see my point).
As far as I know, JUnit will not invoke private test methods, in fact it throws an error when it sees a private method annotated with 'Theory'.
Two suggestions:
Just make the enum public. Since it is in test code it will not be exported in you jar / war so no big deal.
Accept an Object in your test method instead of Lists and cast.