I have a Java class named, MyClass, that I want to test with JUnit. The public method, methodA, that I want to test calls a private method, methodB, in the same class to determine which conditional path to follow. My goal is to write JUnit tests for the different paths in methodA. Also, methodB calls a service, so I do not want it to actually be executed when I run the JUnit tests.
What is the best way to mock methodB and control its return so that I can test different paths for 'methodA'?
I prefer to use JMockit when writing mocks, so I am specifically interested in any answer that applies to JMockit.
Here is my example class:
public class MyClass {
public String methodA(CustomObject object1, CustomObject object2) {
if(methodB(object1, object2)) {
// Do something.
return "Result";
}
// Do something different.
return "Different Result";
}
private boolean methodB(CustomObject custObject1, CustomObject custObject2) {
/* For the sake of this example, assume the CustomObject.getSomething()
* method makes a service call and therefore is placed in this separate
* method so that later an integration test can be written.
*/
Something thing1 = cobject1.getSomething();
Something thing2 = cobject2.getSomething();
if(thing1 == thing2) {
return true;
}
return false;
}
}
This is what I have so far:
public class MyClassTest {
MyClass myClass = new MyClass();
#Test
public void test_MyClass_methodA_enters_if_condition() {
CustomObject object1 = new CustomObject("input1");
CustomObject object2 = new CustomObject("input2");
// How do I mock out methodB here to return true?
assertEquals(myClass.methodA(object1, object2), "Result");
}
#Test
public void test_MyClass_methodA_skips_if_condition() {
CustomObject object1 = new CustomObject("input1");
CustomObject object2 = new CustomObject("input2");
// How do I mock out methodB here to return false?
assertEquals(myClass.methodA(object1, object2), "Different Result");
}
}
Thanks!
To give the answer you asked for (using JMockit's partial mocking):
public class MyClassTest
{
#Tested MyClass myClass;
#Test
public void test_MyClass_methodA_enters_if_condition() {
final CustomObject object1 = new CustomObject("input1");
final CustomObject object2 = new CustomObject("input2");
new NonStrictExpectations(myClass) {{
invoke(myClass, "methodB", object1, object2); result = true;
}};
assertEquals("Result", myClass.methodA(object1, object2));
}
#Test
public void test_MyClass_methodA_skips_if_condition() {
final CustomObject object1 = new CustomObject("input1");
final CustomObject object2 = new CustomObject("input2");
new NonStrictExpectations(myClass) {{
invoke(myClass, "methodB", object1, object2); result = false;
}};
assertEquals("Different Result", myClass.methodA(object1, object2));
}
}
However, I would not recommend doing it like that. In general, private methods should not be mocked. Instead, mock the actual external dependency of your unit under test (the CustomObject in this case):
public class MyTestClass
{
#Tested MyClass myClass;
#Mocked CustomObject object1;
#Mocked CustomObject object2;
#Test
public void test_MyClass_methodA_enters_if_condition() {
new NonStrictExpectations() {{
Something thing = new Something();
object1.getSomething(); result = thing;
object2.getSomething(); result = thing;
}};
assertEquals("Result", myClass.methodA(object1, object2));
}
#Test
public void test_MyClass_methodA_skips_if_condition() {
new NonStrictExpectations() {{
object1.getSomething(); result = new Something();
object2.getSomething(); result = new Something();
}};
assertEquals("Different Result", myClass.methodA(object1, object2));
}
}
Do not be tempted to mock private methods, even if you can engaging in trickery to do so using a mocking tool. Private members are implementation details, which you should be free to change. Instead use the non-private API to exercise the class. If this is troublesome, consider moving the troublesome code into a different class, if it is not there already, and use dependency injection to inject a mock implementation of the troublesome code.
Make methodB a member of a separate class, and have a private reference to that class within MyClass.
public class MyClass {
private MyOtherClass otherObject = new MyOtherClass();
public String methodA(CustomObject object1, CustomObject object2) {
if(otherObject.methodB(object1, object2)) {
// Do something.
return "Result";
}
// Do something different.
return "Different Result";
}
}
class MyOtherClass {
public boolean methodB(CustomObject custObject1, CustomObject custObject2) {
// Yada yada code
}
}
Personally, I usually only test public methods and look at coverage reports to ensure that all paths have been visited in my private methods. If I really need to test a private method, that's a smell that requires a refactoring as I have above.
You could also use reflection, but I'd feel dirty doing that. If you REALLY want the solution to that let me know and I'll add it to this answer.
import org.easymock.EasyMock;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest({ MyClass.class })
public class MyClassTest {
// Class Under Test
MyClass cut;
#Before
public void setUp() {
// Create a new instance of the service under test (SUT).
cut = new MyClass();
// Common Setup
// TODO
}
#Test
public void testMethodA() throws Exception {
/* Initialization */
CustomObject object2 = PowerMock.createNiceMock(CustomObject.class);
CustomObject object1 = PowerMock.createNiceMock(CustomObject.class);
MyClass partialMockCUT = PowerMock.createPartialMock(MyClass.class,
"methodB");
long response = 1;
/* Mock Setup */
PowerMock
.expectPrivate(partialMockCUT, "methodB",
EasyMock.isA(CustomObject.class),
EasyMock.isA(CustomObject.class)).andReturn(true)
.anyTimes();
/* Mock Setup */
/* Activate the Mocks */
PowerMock.replayAll();
/* Test Method */
String result = partialMockCUT.methodA(object1, object2);
/* Asserts */
Assert.assertNotNull(result);
PowerMock.verifyAll();
}
}
To mock the private method, you need powermock
The sample code will be like this, but I haven't run it.
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith (PowerMockRunner.class)
public class MyClassTest {
#Test
public void test_MyClass_methodA_enters_if_condition() {
final MyClass myClass = Mockito.mock (MyClass.class);
CustomObject object1 = new CustomObject("input1");
CustomObject object2 = new CustomObject("input2");
Mockito.when (myClass.methodB(object1, object2)).thenReturn (true);
Mockito.when (myClass.methodA(object1, object2)).thenCallRealMethod ();
assertEquals(myClass.methodA(object1, object2), "Result");
}
}
Related
I am having issues with JUnit test cases. For some reason, I am unable to go to a method of the mocked class and I am not sure why that actually is happening.
import java.util.ArrayList;
import static java.util.UUID.randomUUID;
public class Sample {
protected SomeClass someClass;
public void setVariables(SomeClass someClass) {
this.someClass = someClass;
}
protected UserInfo func(String id){
UserInfo userInfo = someClass.getInfo(id);
// I checked that the someClass is mocked instance
// id is not null
}
}
I am not even going in the following method. I am not sure why that actually is happening which then gives me NPE on above statment.
public class SomeClass{
public UserInfo getInfo(String id) {
// not even going in this function at all
if (id == null || id.isEmpty()) return null;
UserInfo userInfo = null;
try {
// do Something
} catch () {
}
return userInfo;
}
}
class SampleTest{
Sample sample;
SomeClass someclass = mock(SomeClass.class);
UserInfo userinfo = mock(UserInfo.class);
#BeforeEach
void setUp(){
// other initialization
sample = new Sample();
sample.setVariables(someclass);
}
#Test
void func(){
when(someclass.getInfo(randomUUID().toString())).thenReturn(userinfo);
UserInfo userInfo = sample.func(randomUUID().toString());
// comparison using assert
}
}
Wrong when statement.
when(someclass.getInfo(randomUUID().toString())).thenReturn(userinfo)
Some possible solutions:
var randomUuid = randomUUID().toString();
when(someclass.getInfo(anyString())).thenReturn(userinfo)
when(someclass.getInfo(any())).thenReturn(userinfo)
when(someclass.getInfo(eq(randomUuid))).thenReturn(userinfo)
If you mock an instance of the SomeClass, your getInfo code will not be executed, try to use spy instead.
SomeClass someclass = spy(SomeClass.class);
I am testig a public method and I want to verify if a private method, that have mocked params, is called.
All the answers I have found are using invoke method, but this was removed since JMockit v1.36
public class ClassToTest{
public void methodToTest(){
DependencyClass abc = new DependencyClass();
if(privateMethod1()){
privateMethod2(abc);
}
}
private boolean privateMethod1(){ return true; }
private void privateMethod2(DependencyClass abc){ abc.doStuff(); }
}
public class testClassToTest{
#Mocked
DependencyClass abc;
#Tested
ClassToTest testedClass;
#BeforeEach
public void setUp() {
testedClass = new ClassToTest();
}
#Test
public void testMethod(){
new MockUp<ClassToTest>() {
#Mock
private boolean privateMethod1() {
return true;
}
};
testedClass.methodToTest();
new FullVerificationsInOrder() {{
abc = new DependencyClass();
//Check here if privateMethod2(abc) gets called once
}};
}
You can use Powermock to mock and verify private methods.
Please check https://github.com/powermock/powermock/wiki/MockPrivate
You have two ways:
To level up your method's scope from private to package-private and after it, your method will become visible in the test.
Refactoring your code and encapsulate the private method to Predicate and after it, you can test your primary method and Predicate separately.
You can't test the private method by Junit.
I'm not very well-versed with Mockito but am trying to use mocks to test behaviour of a simulation, this is the class:
package simulator;
import java.util.Map;
import org.apache.commons.lang3.Validate;
import simulator.enums.Team;
import simulator.fixtures.Fixture;
public class SimulateBasketballMatchResult implements Simulation<Team> {
private final Fixture fixture;
public SimulateBasketballMatchResult(Fixture fixture) {
Validate.notNull(fixture, "fixture cannot be null");
this.fixture = fixture;
}
#Override
public Team simulate(Map<Team, Double> outcomeProbabilityMap) {
Validate.notNull(outcomeProbabilityMap, "outcomeProbabilityMap cannot be null");
final Team homeTeam = fixture.getHomeTeam();
final Team awayTeam = fixture.getAwayTeam();
double random = randomDoubleGenerator();
double homeWinProbability = outcomeProbabilityMap.get(homeTeam);
return random < homeWinProbability ? homeTeam : awayTeam;
}
public Double randomDoubleGenerator() {
return Math.random();
}
}
Below is the test class:
#RunWith(MockitoJUnitRunner.class)
public class SimulateBasketballMatchResultTest {
#Rule
public ExpectedException expectedException = ExpectedException.none();
private static final Map<Team, Double> MATCH_RESULT_PROBABILITY_MAP = new HashMap<>();
private static final Fixture FIXTURE = new Fixture(GOLDEN_STATE_WARRIORS, HOUSTON_ROCKETS, REGULAR_SEASON);
static {
MATCH_RESULT_PROBABILITY_MAP.put(FIXTURE.getHomeTeam(), 0.7d);
MATCH_RESULT_PROBABILITY_MAP.put(FIXTURE.getAwayTeam(), 0.3d);
}
#Mock
private SimulateBasketballMatchResult simulateBasketballMatchResult;
#Test
public void shouldReturnGoldenStateWarriorsAsWinner() {
when(simulateBasketballMatchResult.randomDoubleGenerator()).thenReturn(0.5d);
assertThat(simulateBasketballMatchResult.simulate(MATCH_RESULT_PROBABILITY_MAP), is(GOLDEN_STATE_WARRIORS));
}
}
I would like to assert that GOLDEN_STATE_WARRIORS is returned when the probability range is between 0 and 0.7- however I get an assertion error of null with my test code.
java.lang.AssertionError:
Expected: is <GOLDEN_STATE_WARRIORS>
but: was null
Expected :is <GOLDEN_STATE_WARRIORS>
simulateBasketballMatchResult is a mock object, so by default, it will return null for all its methods (that have a non-primitive return value, of course).
Instead of mocking that object, you should probably spy it:
#Spy
private SimulateBasketballMatchResult simulateBasketballMatchResult =
new SimulateBasketballMatchResult(Fixture);
Try this:
#Mock
private Fixture fixture;
private SimulateBasketballMatchResult simulator;
#Before
public void setUp() {
simulator = spy(new SimulateBasketballMatchResult(fixture));
doCallRealMethod().when(simulator).simulate();
}
#Test
public void shouldReturnGoldenStateWarriorsAsWinner() {
doReturn(0.5).when(simulator).randomDoubleGenerator();
when(fixture.getHomeTeam()).thenReturn(GOLDEN_STATE_WARRIORS);
when(fixture.getAwayTeam()).thenReturn(HOUSTON_ROCKETS);
assertThat(simulator.simulate(MATCH_RESULT_PROBABILITY_MAP), is(GOLDEN_STATE_WARRIORS));
}
Mockito.spy and #Spy allow you to mock some methods of a real object, but Mockito.mock and #Mock mock the whole object.
A mock in mockito is a normal mock (allows you to stub invocations; that is, return specific values out of method calls).
A spy in mockito is a partial mock (part of the object will be mocked and part will use real method invocations).
Read more
I'm using TestNG and JMockit for testing. My code goes like this:
public boolean testMethod(String a, String b) {
//processing .....
mockClass.mockMethod(a);
//processing....
}
The mockMethod():
Class MockClass {
public void mockMethod(String a) {
//some operations to mock
}
}
I'm using MockUp according to this question: (How to mock public void method using jmockit?)
I'm still getting the NPE. What am I doing wrong? Also, is it because I'm using it like this?
#Test
public void test() {
new Expectations() {
{
//for statements preceding mockMethod()....
new MockUp<MockClass>(){
#Mock
public void mockMethod(String a) {
//do nothing
}
};
}
};
}
I've put it outside Expectations() & used NonStrictExpectations too. How do I fix this?
If the method to be mocked is not returning anything, you don't need to do anything special in expectations. You can define your class to be mocked using #Injectable or #Mocked annotations in usual way. Optionally you can add an expectation to verify the number of times the method is called. Also you can add verification step to capture the argument "a" and do assertions on that. Refer below code sample.
#Tested
private MyClassToBeTested myClassToBeTested;
#Injectable
private MockClass mockClass;
#Test
public void test() {
// Add required expectations
new Expectations() {{
...
..
}};
// Invoke the method to be tested with test values;
String expectedA = "testValueA";
String expectedB = "testValueB";
boolean result = myClassToBeTested.testMethod(expectedA, expectedB);
// Assert the return value of the method
Assert.assertTrue(result);
// Do the verifications and assertions
new Verifications() {{
String actualA;
mockClass.mockMethod(actualA = withCapture()); times = 1;
Assert.assertNotNull("Should not be null", actualA);
Assert.assertEquals(actualA, expectedA);
...
..
}};
}
For void method mocking You can make Expectations without any result as shown below :
#Tested
private MyClassToBeTested myClassToBeTested;
#Injectable
private MockClass mockClass;
#Test
public void test() {
new Expectations() {{
mockClass.mockMethod(anyString);
}};
String inputA = "testValueA";
String inputB = "testValueB";
boolean result = myClassToBeTested.testMethod(inputA, inputB);
assertEquals(true, result);
}
I used to rely on Mockito until today I have a final class with some static methods so I've to switched to JMockit. I knew nothing about it before so the question is: how can I apply the similar logic from Mockito to JMockit?
public final class ServiceData extends BaseData {
private List<Data> data;
public ServiceData(List<Data> data) {
this.data = data;
// something else
}
public static Container getContainer() {
return super.getContainer();
}
public Data getDataAt(Index index) {
return super.getContainer().get(index);
}
}
The test written in Mockito looks like:
#Test
public void test() {
ServiceData mockServiceData = mock(ServiceData.class);
Data mockData = mock(Data.class);
// only stubbing some of the methods
Container mockContainer = spy(Container.class);
doReturn(something).when(mockContainer.someMethod());
when(mockServiceData.getContainer()).thenReturn(mockContainer);
when(mockServiceData.getDataAt(any(Index.class)).thenReturn(mockData);
// some assertions
}
This won't work since Mockito cannot mock final classes nor static methods (getContainer)
So how can I write the same logic in JMockit? Thanks.
The following is the JMockit equivalent for the example test:
#Test
public void test(
#Mocked final ServiceData mockServiceData, #Mocked final Data mockData,
#Mocked final Container mockContainer)
{
// only stubbing some of the methods
new Expectations(mockContainer) {{
mockContainer.someMethod(); result = "something";
mockServiceData.getContainer(); result = mockContainer;
mockServiceData.getDataAt((Index) any); result = mockData;
}};
// some assertions
}
To mock static methods the syntax is the same, except that you would write ServiceData.getContainer(); result = mockContainer; instead.