How to mock different responses from constructor with PowerMock - java

I'm getting an error from PowerMock when running the following:
whenNew(Socket.class).withAnyArguments().thenReturn(server).thenCallRealMethod();
The error is:
You probably stored a reference to OngoingStubbing returned by when() and
called stubbing methods like thenReturn() on this reference more than once.
Examples of correct usage:
when(mock.isOk()).thenReturn(true).thenReturn(false).thenThrow(exception);
when(mock.isOk()).thenReturn(true, false).thenThrow(exception);
Any idea how I can return my mock object on the first new and afterwards call the default constructor?

I don't know about any built-in solution, but try this one, it's supposed to work:
whenNew(Socket.class).withAnyArguments().thenAnswer(new Answer<Object>() {
boolean firstCall;
#Override
public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
if (firstCall) {
firstCall = false;
return server;
}
return invocationOnMock.callRealMethod();
}
});
With thenAnswer you can implement any logic for mocking a method inside an Answer.
So, if you need such a behavior often, I would suggest you encapsulating it into a class like this:
class MockOnlyFirstCall<T> implements Answer<T> {
private final T firstCallResult;
private boolean firstCall = true;
public MockOnlyFirstCall(T firstCallResult) {
this.firstCallResult = firstCallResult;
}
#Override
public T answer(InvocationOnMock invocationOnMock) throws Throwable {
if (firstCall) {
firstCall = false;
return firstCallResult;
}
return invocationOnMock.callRealMethod();
}
}
Then you could just do
whenNew(Socket.class)
.withAnyArguments()
.thenAnswer(new MockOnlyFirstCall<>(server));

Related

Mock or override static method to test a class

I'm doing some unit test but I'm having problems trying to test a class. I have a class with a static builder method which returns the class instance:
public class MessageCaller {
public static MessageCaller builder() {
return new MessageCaller();
}
//Other methods
public String publish() {
//publishing to some Messages
return "something";
}
public MessageCaller withAttribute(String key, String value) {
//Some code
return this;
}
}
public class MessageCallerExtended extends MessageCaller {
private Map<String, String> attributes;
#Override
public MessageCaller withAttribute(String key, String value) {
if (this.attributes == null) {
this.attributes = new HashMap();
}
this.attributes.put(key, value);
return this;
}
//It's not working because it's calling the base class builder and is not possible to be Overriten
//because it's a static method.
public static MessageCallerExtended builder() {
return new MessageCallerExtended();
}
#Override
public String publish() {
return "test";
}
}
This is the method which I would like to test, the problem is that is calling the real publish method taking some time to finalize.
public void sendMessages(#Nonnull String group, #Nonnull String state) {
this.message.builder()
.toTopic(xxxx)
.withAttribute(xxx, xxx)
.withAttribute(xxx, xxx)
.withAttribute(xxx,xxx)
.publish();
}
I'm sending the message object in the constructor of the class.
I've created a Wrapper class to use in the unit test but the problem is that the builder method is static and for that reason is not possible to #Override, if I don't use the #Override tag I'll invoke the real builder method and then the real publish method and it is taking too much time to be processed, causing some problems, because is invoked for several unit test.
With Mockito I having similar issues with the static builder method, in fact it's not possible to mock static methods with Mockito. I'm not allowed to use another library like PowerMock for instance.
Any ideas?

How do I test Function's code when it's passed as method parameter?

Is it possible to test code that is written in lambda function that is passed inside the method process?
#AllArgsConstructor
public class JsonController {
private final JsonElementProcessingService jsonElementProcessingService;
private final JsonObjectProcessingService jsonObjectProcessingService;
private final JsonArrayProcessingService jsonArrayProcessingService;
public void process(String rawJson) {
jsonElementProcessingService.process(json -> {
JsonElement element = new JsonParser().parse(json);
if (element.isJsonArray()) {
return jsonArrayProcessingService.process(element.getAsJsonArray());
} else {
return jsonObjectProcessingService.process(element.getAsJsonObject());
}
}, rawJson);
}
}
Since the lambda is lazy the function is not invoked (Function::apply) when I call JsonController::process so is there any way to check that jsonArrayProcessingService::process is called?
#RunWith(JMockit.class)
public class JsonControllerTest {
#Injectable
private JsonElementProcessingService jsonElementProcessingService;
#Injectable
private JsonObjectProcessingService jsonObjectProcessingService;
#Injectable
private JsonArrayProcessingService jsonArrayProcessingService;
#Tested
private JsonController jsonController;
#Test
public void test() {
jsonController.process("[{\"key\":1}]");
// how check here that jsonArrayProcessingService was invoked?
}
}
Just make it testable (and readable) by converting it to a method:
public void process(String rawJson) {
jsonElementProcessingService.process(this::parse, rawJson);
}
Object parse(String json) {
JsonElement element = new JsonParser().parse(json);
if (element.isJsonArray()) {
return jsonArrayProcessingService.process(element.getAsJsonArray());
} else {
return jsonObjectProcessingService.process(element.getAsJsonObject());
}
}
The relevant guiding principles I personally follow are:
anytime my lambdas require curly brackets, convert them to a method
organise code so that it can be unit tested
You may need to change the return type of the parse method to match whatever your processing services (which you didn’t show) return.
Given its relatively-basic redirection logic, don't you just want to confirm which of the #Injectables got called:
#Test
public void test() {
jsonController.process("[{\"key\":1}]");
new Verifications() {{
jsonArrayProcessingService.process(withInstanceOf(JsonArray.class));
}};
}

How to verify invocations of the same mock method with the same argument that changes state between invocations in mockito?

I have the following code to be unit tested:
public void foo() {
Entity entity = //...
persistence.save(entity);
entity.setDate(new Date());
persistence.save(entity);
}
I would like to verify that on the first invocation of persistence.save entity.getDate() returns null.
Therefore I'm unable to use Mockito.verify(/*...*/) because at that time the method foo already completed and entity.setDate(Date) was called.
So I think I need to do verifications of invocations already at the time the invocations happen. How do I do this using Mockito?
I created the following Answer implementation:
public class CapturingAnswer<T, R> implements Answer<T> {
private final Function<InvocationOnMock, R> capturingFunction;
private final List<R> capturedValues = new ArrayList<R>();
public CapturingAnswer(final Function<InvocationOnMock, R> capturingFunction) {
super();
this.capturingFunction = capturingFunction;
}
#Override
public T answer(final InvocationOnMock invocation) throws Throwable {
capturedValues.add(capturingFunction.apply(invocation));
return null;
}
public List<R> getCapturedValues() {
return Collections.unmodifiableList(capturedValues);
}
}
This answer captures properties of the invocations being made. The capturedValues can then be used for simple assertions. The implementation uses Java 8 API. If that is not available one would need to use an interface that is able to convert the InvocationOnMock to the captured value. The usage in the testcase is like this:
#Test
public void testSomething() {
CapturingAnswer<Void,Date> captureDates = new CapturingAnswer<>(this::getEntityDate)
Mockito.doAnswer(captureDates).when(persistence).save(Mockito.any(Entity.class));
service.foo();
Assert.assertNull(captureDates.getCapturedValues().get(0));
}
private Date getEntityDate(InvocationOnMock invocation) {
Entity entity = (Entity)invocation.getArguments()[0];
return entity.getDate();
}
The capturing that is done by the presented Answer implementation can't be achieved with Mockitos ArgumentCaptor because this is only used after the invocation of the method under test.
In my original comment, this was the answer I had in mind.
The class to be mocked:
class MockedClass{
void save(SomeBean sb){
//doStuff
}
}
The class we'll need to verify the Date object is null.
class SomeBean{
Date date;
Date getDate(){return date;}
void setDate(Date date){this.date=date;}
}
The class under test:
class TestClass{
MockedClass mc;
TestClass(MockedClass mc){this.mc = mc;}
void doWork(){
SomeBean sb = new SomeBean();
mc.save(sb);
sb.setDate(new Date());
mc.save(sb);
}
}
And the test case:
#Test
public void testAnswer(){
MockedClass mc = Mockito.mock(MockedClass.class);
Mockito.doAnswer(new Answer<Void>(){
boolean checkDate = true;
#Override
public Void answer(InvocationOnMock invocation) throws Throwable {
SomeBean sb = (SomeBean) invocation.getArguments()[0];
if(checkDate && sb.getDate() != null){
throw new NullPointerException(); //Or a more meaningful exception
}
checkDate = false;
return null;
}}).when(mc).save(Mockito.any(SomeBean.class));;
TestClass tc = new TestClass(mc);
tc.doWork();
}
The first time through this Answer (The term I should have used in my original comment), this will throw an exception and fail the test case if date is not null. The second time through, checkDate will be false, so the check will not be performed.

Mockito return value based on property of a parameter

Normally when using Mockito I will do something like:
Mockito.when(myObject.myFunction(myParameter)).thenReturn(myResult);
Is it possible to do something along the lines of
myParameter.setProperty("value");
Mockito.when(myObject.myFunction(myParameter)).thenReturn("myResult");
myParameter.setProperty("otherValue");
Mockito.when(myObject.myFunction(myParameter)).thenReturn("otherResult");
So rather than when just using the parameter to determine the result. It is using a value of a property inside the parameter to determine the result.
So when the code is executed it behaves like so:
public void myTestMethod(MyParameter myParameter,MyObject myObject){
myParameter.setProperty("value");
System.out.println(myObject.myFunction(myParameter));// outputs myResult
myParameter.setProperty("otherValue");
System.out.println(myObject.myFunction(myParameter));// outputs otherResult
}
Here is the current solution, hopefully something better can be suggested.
private class MyObjectMatcher extends ArgumentMatcher<MyObject> {
private final String compareValue;
public ApplicationContextMatcher(String compareValue) {
this.compareValue= compareValue;
}
#Override
public boolean matches(Object argument) {
MyObject item= (MyObject) argument;
if(compareValue!= null){
if (item != null) {
return compareValue.equals(item.getMyParameter());
}
}else {
return item == null || item.getMyParameter() == null;
}
return false;
}
}
public void initMock(MyObject myObject){
MyObjectMatcher valueMatcher = new MyObjectMatcher("value");
MyObjectMatcher otherValueMatcher = new MyObjectMatcher("otherValue");
Mockito.when(myObject.myFunction(Matchers.argThat(valueMatcher))).thenReturn("myResult");
Mockito.when(myObject.myFunction(Matchers.argThat(otherValueMatcher))).thenReturn("otherResult");
}
In Java 8 it is even simpler than all of the above:
when(mockObject.myMethod(anyString()))
.thenAnswer(invocation ->
invocation.getArgumentAt(0, String.class));
Here's one way of doing it. This uses an Answer object to check the value of the property.
#RunWith(MockitoJUnitRunner.class)
public class MyTestClass {
private String theProperty;
#Mock private MyClass mockObject;
#Before
public void setUp() {
when(mockObject.myMethod(anyString())).thenAnswer(
new Answer<String>(){
#Override
public String answer(InvocationOnMock invocation){
if ("value".equals(theProperty)){
return "result";
}
else if("otherValue".equals(theProperty)) {
return "otherResult";
}
return theProperty;
}});
}
}
There's an alternative syntax, which I actually prefer, which will achieve exactly the same thing. Over to you which one of these you choose. This is just the setUp method - the rest of the test class should be the same as above.
#Before
public void setUp() {
doAnswer(new Answer<String>(){
#Override
public String answer(InvocationOnMock invocation){
if ("value".equals(theProperty)){
return "result";
}
else if("otherValue".equals(theProperty)) {
return "otherResult";
}
return theProperty;
}}).when(mockObject).myMethod(anyString());
}
Yes you can, using a custom argument matcher.
See the javadoc of Matchers for more details, and more specifically ArgumentMatcher.
Here is how it would look like in Kotlin with mockito-kotlin library.
mock<Resources> {
on {
mockObject.myMethod(any())
} doAnswer {
"Here is the value: ${it.arguments[0]}"
}
}
You can do this with Mockito 3.6.0:
when(mockObject.myMethod(anyString()))
.thenAnswer(invocation -> myStringMethod(invocation.getArgument(0)));
This answer is based on Sven's answer and Martijn Hiemstra's comment, with getArgumentAt() changed to getArgument().

How to create own annotation for junit that will skip test if concrete exception was thrown during execution?

My application have several execution modes, and in 1 mode it is normal that some of my tests will throw a concrete exception. I need to annotate this methods with something like #SkipOnFail that will set method as skipped if exception was thrown.
thanks in advance!
#Edit(for my question to be more clear)
#Test(expected=ConcreteException.class)
does not work for me because i need my tests to pass even if ConcreteException.class was not thrown(expected tag in junit will mark my test as failed if this exception won't be thrown), and to be skipped otherwise. In all other cases it should work as always.
#Solution that worked for me(junit v4.7) thx to #axtavt
#Rule
public MethodRule skipRule = new MethodRule() {
public Statement apply(final Statement base, FrameworkMethod method, Object target) {
if(method.getAnnotation(SkipOnFail.class) == null) return base;
return new Statement() {
#Override
public void evaluate() throws Throwable {
try{
base.evaluate();
} catch (ConcreteException e) {
Assume.assumeTrue(false);
}
}
};
}
};
#Thx
I don't think that such a feature is available out of the box, but it should be pretty easy to implement with custom TestRule and Assume, something like this:
#Rule
public TestRule skipRule = new TestRule() {
public Statement apply(final Statement base, Description desc) {
if (desc.getAnnotation(SkipOnFail.class) == null) return base;
return new Statement() {
public void evaluate() throws Throwable {
try {
base.evaluate();
} catch (MyExceptoion ex) {
Assume.assumeTrue(false);
}
}
};
}
};
What about using JUnit Extensions?
The following example is taken from their Tutorial.
It provides aditional annotations for Prerequisites (#Prerequisite): Ignore tests based on conditions.
The required approach would be to check this during running tests. So you can simply add a #Prerequisite(requires="") annotation.
public class TestFillDatabase {
#Prerequisite(requires = "databaseIsAvailable")
#Test public void fillData() {
// ...
}
public boolean databaseIsAvailable() {
boolean isAvailable = ...;
return isAvailable;
}
}
public class TestFillDatabase {
#Prerequisite(requires = "databaseIsAvailable")
#Test public void fillData() {
// ...
}
public boolean databaseIsAvailable() {
boolean isAvailable = ...;
return isAvailable ;
}
}
This specified methods with #Prerequisite(requires = "databaseIsAvailable") must be a public method, returning a boolean or Boolean value.
If these methods will be consolidated in helper classes, you can also specify static methods within a class to be called using #Prerequisite(requires = "databaseIsAvailable", callee="DBHelper").
public class TestFillDatabase {
#Prerequisite(requires = "databaseIsAvailable", callee="DBHelper")
#Test public void fillData() {
// ...
}
}
public class DBHelper {
public static boolean databaseIsAvailable() {
boolean isAvailable = ...;
return isAvailable ;
}
}
Also using the Assume class (since jUnit 4.4), you can use assumeNoException():
try{
base.evaluate();
} catch (ConcreteException e) {
Assume.assumeNoException("Concrete exception: skipping test", e);
}
I searched for the docs about JUnit and it appears that from version 4.9 they have introduced what they call test rules (see TestRule). You may start from this.
The ExpectedException class marked as #Rule could be of some help in order to check for exceptions thrown but not mandatory for the test to pass.
For more advanced usage I cannot say for the moment as I've just discovered it.

Categories

Resources