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;
Related
I'm trying to implement a service which calls an object collaborator in TDD, verifying the interaction. The actual code is more complex than this but the example should do.
I used Java and Mockito but the question is not about technology.
I got the following code after the first TDD iteration:
// ServiceTest.java
public class ServiceTest {
private final SomeObject someObject = Mockito.mock(SomeObject.class);
private final Service service = new Service(someObject);
#Test
void handle_verify_call_to_SomeObject() {
Body body = new Body();
body.setSomeString("some parameter");
service.handle(body);
verify(someObject).call("some parameter");
}
}
// Body.java
public class Body {
private String someString;
// getter and setter omitted
}
// Service.java
public class Service {
private final SomeObject someObject;
public void handle(Body body) {
someObject.call("some parameter");
}
}
Is there a way (given a a strict TDD perspective) to pass the correct parameter to someObject.call(...) without adding one more test or parameterize the test with a different someString parameter?
Is it fine to consider implementing the actual code in this case a refactor step? In fact, the test is green before and after the implementation.
I'm finding myself in this situation a lot lately so I decided to ask to the SO community.
Thanks in advance!
This question already has answers here:
How to mock constructor with PowerMockito
(1 answer)
Mock a constructor with parameter
(7 answers)
Closed 2 years ago.
I have a class that's composed of other objects/dependencies as follows:
public class One{
private RedisPool redisPool;
private static final WeakHashMap<String, Dedup<String>> CACHE = new WeakHashMap<>();
private static final ObjectMapper mapper = new ObjectMapper();
private BigQueryManager bigQueryManager;
private RedisClientManager redisClientManager;
private PubSubIntegration pubSub;
public One(RedisPool redisPool, Configuration config) {
this.redisPool = redisPool;
bigQueryManager = new BigQueryManager(config);
redisClientManager = new RedisClientManager(redisPool, config);
pubSub = new PubSubIntegration(config);
}
....
...
other methods
}
I tried:
public class OneTest{
#Mock
RedisPool redisPool;
#Mock
Configuration config;
#Before
public void setUp(){
MockitoAnnotations.initMocks(this);
One one = new One(redisPool, config);
}
}
But I'm not sure whether the objects constructed inside the constructor also get mocked, as I have used those objects in other methods inside the class.
How can I mock the objects constructed inside the constructor?
I don't think you can achieve this using Mockito alone, but you can if you also use PowerMockito.
This article gives an example that is quite similar to what you want to achieve.
Note that PowerMockitio will mess up any test coverage statistics that you are collecting.
EDIT
If the article disappears, the gist of it is that you need to annotate your Test class slightly differently
#RunWith(PowerMockRunner.class)
#PrepareForTest(One.class)
public class OneTest {
The #PrepareForTest annotation refers to the Class that you need to alter the bahaviour of - in your case the One class.
You then tell PowerMoncito to return an object you can control when a new instance is created. In your case
PowerMockito.whenNew(BigQueryManager.class)
.withAnyArguments().thenReturn(mockBigQueryManager);
I have to deal with a legacy application that has no tests. So before I begin refactoring I want to make sure everything works as it is.
Now imagine the following situation:
public SomeObject doSomething(final OtherObject x, final String something) {
if(x != null) {
final String = someOtherMethod(x, something);
}
}
protected String someOtherMethod(final OtherObject x, final String something) {
....
}
Now I want to make sure that protected method is called as well
So I did this
#InjectMocks // Yes there is more going on here
private MyTestObject myTestObject;
private MyTestObject spy;
private static final OtherObject VALID_OTHER_OBJECT = new OtherObject();
#Before
public void setup() {
this.spy = Mockito.spy(myTestObject);
}
#Test
public void ifOtherObjectIsNotNullExpectSubMethodToBeCalled() {
myTestObject.doSomething(VALID_OTHER_OBJECT, null);
verify(spy).someOtherMethod(VALID_OTHER_OBJECT, null);
}
I get a failing test and "Wanted but not invoked..." for someOtherMethod().
I jumped right into debug mode and checked. That method is called!
What could be the cause of this? Am I misusing the spy here?
Edit: I want to stretch that I know this is not what you typically test for, especially since someOtherMethod(...) has a non-void return-value here. But imagine the return value was void...
Basically I just want to understand why the spy fails here.
As per its Javadoc, Mockito.spy(object) creates a copy of the passed in object. Calling methods on the original passed in object then does not register on the spy, because the spy instance is not the same object.
Change myTestObject.doSomething(...) to spy.doSomething(...) and it should work.
Alternative (different way to achieve the same thing):
Consider using the #Spy annotation on your myTestObject.
Be sure to add MockitoAnnotations.initMocks(this); to your initialization method (in your junit test).
The #Before and #Mock annotations are useful as well.
I had one object creating another and that other object making calls. So I needed to make that internal object be using the spied reference instead. I used reflection and updated the reference using Whitebox.
TestAddressFragment fragment = spy(new TestAddressFragment());
AddressPresenter presenter = fragment.getPresenter();
Whitebox.setInternalState(presenter, "view", fragment );
Now my fragment could check if its method was called.
verify( fragment ).showAddress(any(), anyBoolean());
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 am using mockito as mocking framework. I have a scenerio here, my when(abc.method()).thenReturn(value) does not return value, instead it returns null.
public class DQExecWorkflowServiceImplTest {
#InjectMocks
DQExecWorkflowServiceImpl dqExecWorkflowServiceImpl = new DQExecWorkflowServiceImpl();
#Mock
private DQUtility dqUtility;
#Mock
private DqExec dqExec;
#Mock
private DqCntlDefn dqCntlDefn;
#Mock
private DqCntlWfDefn dqCntlWfDefn;
#Mock
private DqCntlWfDefnTyp dqCntlWfDefnTyp;
#Mock
private IDQControlWfDefTypeService controlWfDefTypeService;
#Before
public void setUp() throws Exception {
dqExec = new DqExec();
dqCntlWfDefn = new DqCntlWfDefn();
dqUtility = new DQUtility();
dqCntlWfDefnTyp = new DqCntlWfDefnTyp();
dqCntlWfDefnTyp.setDqCntlWfDefnTypCd("MIN_INCLUSIVE_VAL");
dqExecWorkflowServiceImpl
.setControlWfDefTypeService(controlWfDefTypeService);
}
#Test
public void testExecuteWorkflow() {
when(controlWfDefTypeService.getDqCntlWfDefnTypCd(dqCntlWfDefn))
.thenReturn(dqCntlWfDefnTyp);
dqExecWorkflowServiceImpl.executeWorkflow(dqExec, dqCntlWfDefn);
}
}
Java class
#Override
public DqCntlWfExec executeWorkflow(final DqExec dqExec,
final DqCntlWfDefn dqCntlWfDefn) {
final DqCntlWfExec dqCntlWfExec = new DqCntlWfExec();
dqCntlWfExec.setDqCntlWfExecEffDt(dqUtil.getDefaultEffectiveDt());
dqCntlWfExec.setDqCntlWfExecExpDt(dqUtil.getDefaultExpiryDt());
dqCntlWfExec.setDqCntlWfDefn(dqCntlWfDefn);
dqCntlWfExec.setDqExec(dqExec);
final DqCntlWfDefnTyp dqCntlWfDefnTyp = controlWfDefTypeService
.getDqCntlWfDefnTypCd(dqCntlWfDefn);
String workflowType = null;
if(null!=dqCntlWfDefnTyp){
workflowType = dqCntlWfDefnTyp.getDqCntlWfDefnTypCd();
}
When ever i run the test file the when is not working and i am using mockito1.8.5 jar in the buildpath. The service call is being mocked but returns the null value.
final DqCntlWfDefnTyp dqCntlWfDefnTyp = controlWfDefTypeService
.getDqCntlWfDefnTypCd(dqCntlWfDefn);
This object dqCntlWfDefnTyp is null
I have done this before and there was no problem with the when, It seems to be working with files i have done before. I had followed the same procedure for the test file but i couldnt figure out the issue. Can anyone please assist me
Thanks to all the folks in advance
Mockito mock works when we mock the objects loosely.
Here is the change i have made to make it work:
when(controlWfDefTypeService.getDqCntlWfDefnTypCd(any(DqCntlWfDefn.class))
.thenReturn(dqCntlWfDefnTyp);
Instead of passing the object of the Mock class, I passed the class with the Matcher any() and it works.
TL;DR If some arguments in your test are null, be sure to mock the parameter call with isNull() instead of any(SomeClass.class).
Explanation
This might not be the answer that helps OP, but might be useful for someone else. In my case the setup was all good, however, some mocks returned the desired thenReturn(...) value and some didn't.
It's important to understand, that the method call you're trying to mock (i.e. the method in when(someMock.methodToMock)) has to match the actual call and not the signature only.
In my case, I mocked a method with a signature:
public void SomeValue method(String string, SomeParam param)
The call however, in the test was something like:
method("some string during test", null);
Now if you mock the call with:
when(MockedClass.method(anyString(), any(SomeParam.class))
Mockito will not match it even though the signature is correct. The problem is that Mockito is looking for a call of method() with the arguments String and SomeParam, whereas the actual call was with a String and null. What you have to do is:
when(MockedClass.method(anyString(), isNull())
Hint
Since there are many isNull() implementations in different frameworks, be sure to use this one org.mockito.ArgumentMatchers.isNull.
I think I have found your issue, but not all the credit goes to me.
Since you are trying to mock 'dqCntlWfDefnTyp' in your test class and the object itself is being instantiated in the class that you are trying to test, you inevitably run into some issues. The primary problem is that the object cannot be mocked because it is being recreated in during the test.
There are a few options, but the best choice in my humble opinion is using PowerMockito. You will be able to replace the object within the class that is being tested with the one you mock.
An excellent example of this usage of PowerMockito from #raspacorp on this question:
public class MyClass {
void method1{
MyObject obj1=new MyObject();
obj1.method1();
}
}
And the test class...
#RunWith(PowerMockRunner.class)
#PrepareForTest(MyClass.class)
public class MyClassTest {
#Test
public void testMethod1() {
MyObject myObjectMock = mock(MyObject.class);
when(myObjectMock.method1()).thenReturn(<whatever you want to return>);
PowerMockito.whenNew(MyObject.class).withNoArguments().thenReturn(myObjectMock);
MyClass objectTested = new MyClass();
objectTested.method1();
... // your assertions or verification here
}
}
I had the same problem. The solution for me was to put the Mockito.when(...).thenReturn(...); into the #Before-SetUp method.
Just like Younes EO said: it usually is related to null arguments being passed to mocked functions.
One thing worth adding is that if you're using Kotlin for your tests (and you have mockito-kotlin in your project), for Nullable arguments you should usually use anyOrNull() instead of any().
Relevant to the topic, just in case this helps someone. My mockito.when wasn't working when asserting anyString() reason being the String within the tested class was an injected value from a properties file. The following line set the injected value in the unit test:
ReflectionTestUtils.setField(bean, "theVariable", "theValue");
I haved the same problem when i make test for controler. Use #MockBean instead #Mock