How to mock new() call in Mockito? - java

Its my early days with Mockito so need help. Because of the new() operator, a new object is getting created and the Mock is losing significance. Goal is to prevent execution of the stockValidator.validateRequest() method. Kindly note source code can't be modified.
Sample code shared below,
Is there a way to mock the new() object?
StockResponse buyStock(StockRequest stockRequest) method{
.......
StockValidator stockValidator = new StockValidator(.....);
StockError error = stockValidator.validateRequest(StockRequest stockRequest);
}
StockError validateRequest(StockRequest stockRequest){
......
......
}
#MockBean
StockValidator stockValidator;
#Autowire
StockService stockService;
............
............
when(cardValidator.validateRequest(any(), any())).thenReturn(null);
StockResponse response = stockService.buyStock(stockRequest);

Yes, there is a way to do what you will. Firstly, you do not need to use a spy. A spy is not a mock object. It is an instance on which you can call methods as you would normally, but with additional features.
so do not initialise stockValidator like that, but as:
stockValidator = mock(StockValidator.class);
Or since you are already using #MockBean, you do not have to initialise manually at all.
Mock object will NOT call the actual method, instead just make it return the value you tell it to return.
Now you can allow the validateRequest() method return anything. Possibly
when(stockValidator.validateRequest(any(), any())).thenReturn(true);
Do not forget to initialise the service instance with the same validator object.
edit after change in question:
public class TestClass() {
StockValidator stockValidator = mock(StockValidator.class);
StockService stockService = new StockService(stockValidator);
public void test() {
when(stockValidator.validateRequest(any(),
any())).thenReturn(true);
stockService.buyStock();
}
}

Related

Java, Mockito: Field mocked via #InjectMocks does not notice new value written into the real variable

I have not much experience with Mockito - and I found some behaviour which I can not explain: I have a simple class let's say like this
public class Testee {
protected MyParam myParam;
public void myMethod(){
myParam = new MyParam();
myParam.someField = "a new value";
}
The type of the variable myParam in this class is a class with, let's say, only one pubic field:
public class MyParam {
public String someField;
}
Now I want to write a test for the Testee class and I do it like this:
#RunWith(PowerMockRunner.class)
public class TestTestee {
#InjectMocks
Testee testee = new Testee();
#Mock
MyParam myParam;
#Test
public void testMyMethod(){
myParam.someField = "old value";
testee.myMethod();
assertEquals("a new value", myParam.someField);
}
}
But this test fails! The resulting message is:
org.junit.ComparisonFailure:
Expected: a new value
Actual: old value
So, the mock is actually injected correctly, but it does not seem to notice, that the method in the real class writes a new value into the mocked variable (myParam = new MyParam();). The value of the mock remains the same - and the test fails. This is a bit confusing to me, especially regarding, that if I simply remove the line myParam = new MyParam();, then the test succeeds!
So, the mock is not able to notice a new object being written into the mocked variable, but it does notice changes made to the object - do I understand it correctly? And what would be the proper way to test the value written into myParam by myMethod() in this case?
This is happening because on the line in Testee where myParam = new MyParam(), the reference to the class member Testee testee is reassigned to new MyParam(). The mock object in the test has not been reassigned and still points to the original value.
To resolve this, you could add setter setSomeField(String someField) to MyParam and instead of reassigning the value, in Testee, call myParam.setSomeField("a new value").
So, the mock is not able to notice a new object being written into the
mocked variable, but it does notice changes made to the object - do I
understand it correctly?
It's all about which object in memory that the reference is pointed to. In the test, we create a mock and the mocking framework sets the class member to the object reference of the mock.
We then reassign the class member but our unit test checks the mock. The mock's object reference has not been changed.
It seems you do not really need a mock here as you want to pass an object with a certain state. You might reconsider and simply use a setter.
If you really have to and possibly need to mock some of the public methods of that class then try to use a spy instead of a mock:
#Spy
MyParam myParam;
Now by default, all the real implementation will be called and you need to mock explicitly certain methods that you want to be stubbed.

Mockito: Mocking different classes method in a specific class scope

I'd like to do this mocking with Mockito
MyServiceClass
(this isn't the actual code, just a fake example with a similar intent)
public String getClassObjects() {
OtherClassObject otherclass = OtherClassObject.createOtherClassObject();
String id = otherclass.getParentObject().getId();
return id;
}
So essentially I want to mock ".getId()" but only in the context of this class "MyServiceClass" if I call the same method of "getId()" in a different class I want to be able to mock a different return.
This will return "3" in every method call for the OtherClassObject
new MockUp<MyServiceClass>() {
#Mock
public String getId(){
return "3";
}
};
Is there a way to isolate method calls for a class object within the scope of a specific class?
Plain Mockito is unable to mock static calls, so you need PowerMock here. To achieve desired you should return different values from the mocked object like this
// from your example it's not clear the returned type from getParentObject method.
// I'll call it ParentObj during this example. Replace with actual type.
ParentObj poOne = mock(ParentObj.class);
when(poOne.getId()).thenReturn("3");
ParentObj poTwo = mock(ParentObj.class);
when(poTwo.getId()).thenReturn("10");
...
OtherClassObject otherClassObjectMock = mock(OtherClassObject.class);
// return all your stubbed instances in order
when(otherClassObjectMock.getParentObject()).thenReturn(poOne, poTwo);
PowerMockito.mockStatic(OtherClassObject.class);
when(OtherClassObject.createOtherClassObject()).thenReturn(otherClassObjectMock);
Thus, you can customize your mocks per needs, specifying desired return value, or propagating call to actual (real) method.
Don't forget to use annotations #RunWith(PowerMockRunner.class) and #PrepareForTest(OtherClassObject.class) on class level to activate the magic of PowerMock.
An alternative idea is to get rid of static call inside your getClassObjects method and pass factory using constructor, so you can easily mock it, setting mocked object only for single class.
Hope it helps!

Calling method on real object instead calling on Mock object

I faced next issue when I have been writing Junit tests with using Mockito. My test invokes methods on real object instead mock object and I receive NullPointerException. Here is my code:
public class JSFUtilsTest {
public JSFUtilsTest() { }
JSFUtils jsfUtils = mock(JSFUtils.class);
FacesContext facesContext = ContextMocker.mockFacesContext();
ExternalContext extContext = mock(ExternalContext.class);
Application app = mock(Application.class);
ExpressionFactory exFactory = mock(ExpressionFactory.class);
ELContext elContext = mock(ELContext.class);
ValueExpression valExp = mock(ValueExpression.class);
#Test
public void testResolveExpression() {
when(jsfUtils.resolveExpression("expression")).thenAnswer(new Answer<Object>(){
public Object answer(InvocationOnMock invocation){
when(facesContext.getApplication()).thenReturn(app);
when(app.getExpressionFactory()).thenReturn(exFactory);
when(facesContext.getELContext()).thenReturn(elContext);
when(exFactory.createValueExpression(elContext, "expression", Object.class)).thenReturn(valExp);
when(valExp.getValue(elContext)).thenReturn(anyObject());
return valExp.getValue(elContext);
}
});
jsfUtils.resolveExpression(anyString());
verify(jsfUtils).resolveExpression(anyString());
assertNotNull(jsfUtils.resolveExpression(anyString()));
}
}
Instead calling resolveExpression() on Mock, I have got calling on JSFUtils object. JSFUtils.java and JSFUtilsTest.java are located in different packages. Can anybody help me? Thanks in advance!
I assume that this is just an example and in real test you do not call methods on the mock directly, but inject the dependencies to OUT.
You are expecting your mock to answer when you are calling jsfUtils.resolveExpression("expression"). In fact you are not calling it. I would suggest to change it to jsfUtils.resolveExpression(anyString()) and if you need it to be called with some specific string, you can check it the verify block: verify(jsfUtils).resolveExpression("expression");
Also calling jsfUtils.resolveExpression(anyString()); is not the right approach. Method anyString() is designed for stubbing not for real call.
Instead calling resolveExpression() on Mock, I have got calling on JSFUtils object.
Then do not create a mock, but a spy:
//JSFUtils jsfUtils = mock(JSFUtils.class);
JSFUtils jsfUtils = spy(new JSFUtils(/* mocks of dependencies if needed */));
But this is only needed if want to mock the return value of some other method in your class under test to force isolation of your unit.
This is not the case in your example as far as I see. So just write:
//JSFUtils jsfUtils = mock(JSFUtils.class);
JSFUtils jsfUtils = new JSFUtils(/* mocks of dependencies if needed */);
#Test
public void testResolveExpression() {
when(jsfUtils.resolveExpression("expression")).thenAnswer(new Answer<Object>(){
public Object answer(InvocationOnMock invocation){
when(facesContext.getApplication()).thenReturn(app);
when(app.getExpressionFactory()).thenReturn(exFactory);
when(facesContext.getELContext()).thenReturn(elContext);
when(exFactory.createValueExpression(elContext, "expression", Object.class)).thenReturn(valExp);
when(valExp.getValue(elContext)).thenReturn(anyObject());
return valExp.getValue(elContext);
}
});
jsfUtils.resolveExpression(anyString());
verify(jsfUtils).resolveExpression(anyString());
assertNotNull(jsfUtils.resolveExpression(anyString()));
This does not make any sense:
You mock the method of your class under test (cut) and then call that very same method. This way you do not verify the behavior of your cut but the behavior of the mocking framework.
Also you call the method twice within the same test method. You should avoid that.
You should change your test to this:
#Test
public void testResolveExpression() {
// arrange (test case specific setup of mocks and DTOs)
when(facesContext.getApplication()).thenReturn(app);
when(app.getExpressionFactory()).thenReturn(exFactory);
when(facesContext.getELContext()).thenReturn(elContext);
when(exFactory.createValueExpression(elContext, "expression", Object.class)).thenReturn(valExp);
when(valExp.getValue(elContext)).thenReturn(anyObject());
// act (call real method on real object)
Object result = jsfUtils.resolveExpression("a valid input");
// assert
assertNotNull(result );
}

Mocking a local object inside a method of SUT using Mockito or PowerMocktio

I've class method like below which creates a local object and calls a method on that local object.
public class MyClass {
public someReturn myMethod(){
MyOtherClass otherClassObject = new MyOtherClass();
boolean retBool = otherClassObject.otherClassMethod();
if(retBool){
// do something
}
}
}
public class MyClassTest {
#Test
public testMyMethod(){
MyClass myClassObj = new MyClass();
myClassObj.myMethod();
// please get me here..
}
}
When I'm testing myMethod, I want to mock otherClassObject.otherClassMethod to return something of my choice. otherClassMethod does some class to Message Queues and I don't want that in Unit test. So I want to return true when I do otherClassObj.otherClassMethod(). I know I must have used a factory for MyOtherClass instantiation in this case but it's legacy code and I don't want to change any code now. I see that Mockito doesn't provide this facility to mock MyOtherClass in this case but possible with PowerMockito. However, I could not find an example for above scenario but found only for static class. How should I mock local object inside a method of SUT ?
I also referred to some other OS questions like - Mocking methods of local scope objects with Mockito but they were not helpful.
A code example will be of great help.
If you are using PowerMockito you can use the whenNew method
It should look something like this:
#RunWith(PowerMockRunner.class)
#PrepareForTest(MyClass.class) //tells powerMock we will modify MyClass to intercept calls to new somewhere inside it
public class MyClassTest{
#Test
public void test(){
MyOtherClass myMock = createMock(MyOtherClass.class);
//this will intercept calls to "new MyOtherClass()" in MyClass
whenNew( MyOtherClass.class).withNoArguments().thenReturn( myMock) );
... rest of test goes here
}
Also this other SO post has example code too PowerMockito Mocking whenNew Not taking affect
OK, this is not a real answer but with PowerMockito you can do this:
final MyOtherClass myOtherClass = mock(MyOtherClass.class);
// mock the results of myOtherClass.otherClassMethod();
PowerMockito.whenNew(MyOtherClass.class).withNoArguments()
.thenReturn(myOtherClass);
// continue with your mock here
Now, not sure whether you actually need the result of this otherClassMethod here, but if you don't, I'd suggest you mock the results of myMethod() instead -- unless myMethod() is what you want to test because this other method has an influence on it, and yes, in this case a refactoring should be considered... And not delayed ad vitam aeternam...

Unit Testing Java Code - Mocking a non-static method of a different class

public class First {
public First(){
}
public String doSecond(){
Second second = new Second();
return second.doJob();
}
}
class Second {
public String doJob(){
return "Do Something";
}
}
Here I want to test the method "doSecond()" of class "First". For the same, I want to mock the method "doJob" of class "Second".
I know that I can create a mocked instance of class "Second" using the code below.
Second sec = mock(Second.class);
when(sec.doJob()).thenReturn("Stubbed Second");
But I cannot relate this mocked instance with class "First" as of the current code.
Without refactoring the source code, is there any way by which i can achieve the requirement.
Please help.
Take a look at powermock's ability to intercept calls to new and return mocks instead
https://code.google.com/p/powermock/wiki/MockConstructor
This doesn't require changing any sourcecode.
here's the test code where we actually return a mock when First.doSecond() calls new Second()
#RunWith(PowerMockRunner.class)
#PrepareForTest(First.class)
public class TestFirst {
#Test
public void mockSecond() throws Exception{
Second mock = PowerMockito.mock(Second.class);
PowerMockito.whenNew(Second.class).withNoArguments().thenReturn(mock);
PowerMockito.when(mock.doSecond()).thenReturn("from mock");
First first = new First();
assertEquals("from mock", first.doSecond());
}
}
It's tricky to mock an instance that you create inside of a method, but it's possible.
Using PowerMock, you can accomplish this with the PowerMock.expectNew() method:
#RunWith(PowerMockRunner.class)
#PrepareForTest(First.class)
public class StackOverflowTest {
#Test
public void testFirst() throws Exception {
Second secondMock = EasyMock.createMock(Second.class);
PowerMock.expectNew(Second.class).andReturn(secondMock);
expect(secondMock.doSecond()).andReturn("Mocked!!!");
PowerMock.replay(secondMock, Second.class);
String actual = new First().doSecond();
PowerMock.verify(secondMock, Second.class);
assertThat(actual, equalTo("Mocked!!!"));
}
}
Effectively, PowerMock is proxying the creation of the new object and substituting whatever value we want when we invoke doSecond().
So, it's possible. However, this is a terrible practice to get into.
One typically wants to mock objects if they involve an outside concern, such as another layer (i.e. database, validation), or if the desired output is coming from other objects that are injected but are safe enough to consider tested.
If your method is capable of getting or retrieving data from a non-injectable source, you should not want to mock that out.
Considering that your method is simple and straightforward, you should really not need to do any mocks here at all. But if you felt that you were forced to, you could do one of a few things:
Create a factory for the creation of Second, and mock the results of the returning factory object with Mockito.
Pass in an instance of Second to that method, and use Mockito as the mock instance.
Declare it as a field (i.e. injected dependency), and use Mockito.
For completeness, here is how the test can be written with the JMockit mocking API, without any refactoring of the original code under test:
public class ExampleTest
{
#Test
public void firstShouldCallSecond(#Mocked final Second secondMock) {
new NonStrictExpectations() {{
secondMock.doJob(); result = "Mocked!!!";
}};
String actual = new First().doSecond();
assertEquals("Mocked!!!", actual);
}
}

Categories

Resources