Mockito not matching arguments when stubbed with functional interface - java

I am having trouble mocking a service dependency that accepts a functional interface in a method. I have simplified the problem to the follow test application. Mockito is not matching on the passed in lambda method reference. I have tried various ways of passing in a reference to the stubbing.
package com.example.test;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.function.Function;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;
#FunctionalInterface
interface MyCallback<T> extends Function<String, T> {
T apply(String s);
}
interface MyDependency {
<T> T submit(String id, MyCallback<T> myCallback);
}
class MyService {
private final MyDependency myDependency;
MyService(MyDependency myDependency) {
this.myDependency = myDependency;
}
String run() {
MyCallback<String> myCallback = getStringMyCallback();
return myDependency.submit("myId", myCallback);
}
public MyCallback<String> getStringMyCallback() {
return s -> "hello " + s;
}
}
#ExtendWith(MockitoExtension.class)
class TestUtil {
#Mock
private MyDependency myDependency;
#InjectMocks
private MyService myService;
#Test
void test() {
MyCallback<String> myCallback = myService.getStringMyCallback();
when(myDependency.submit("id", myCallback)).thenReturn("world");
String value = myService.run();
assertThat(value).isEqualTo("world");
}
}
The desired outcome is to pass a method lambda to the myDependency and stub different results. In this code the contents of 'value' is null.

Related

How do I convert this test rule to JUnit5?

I have some custom rule using junit4 which I would like to convert to junit5. However I'm not able to find good documentation on migrating a MethodRule implementation other than that I should be using junit5 extension instead of rule.
public class MyRule implements MethodRule {
private static final Logger LOGGER = LoggerFactory.getLogger(MyRule.class);
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface MyAnnotation { }
#Override
public Statement apply(final Statement statement, final FrameworkMethod frameworkMethod, final Object o) {
Statement result = statement;
if (hasMyAnnotation(frameworkMethod)) {
result = new Statement() {
#Override
public void evaluate() {
LOGGER.info("Skipping test");
}
};
}
}
return result;
}
private static boolean hasMyAnnotation(final Annotatable frameworkMethod) {
return frameworkMethod.getAnnotation(MyAnnotation.class) != null;
}
My class is using junit4 Statement, FrameworkMethod etc to find out if my method has an annotation... then to skip it. How can I convert this?
Solution 1, Disable test with custom annotation
JUnit 5 provides a type of extension that can control whether or not a test should be run. This is defined by implementing the ExecutionCondition interface.
Extension implementation:
import org.junit.jupiter.api.extension.ConditionEvaluationResult;
import org.junit.jupiter.api.extension.ExecutionCondition;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.platform.commons.logging.Logger;
import org.junit.platform.commons.logging.LoggerFactory;
import org.junit.platform.commons.util.AnnotationUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
public class SkipConditionExtension implements ExecutionCondition {
private static final Logger LOGGER = LoggerFactory.getLogger(SkipConditionExtension.class);
#Override
public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {
AnnotatedElement element = context.getElement().orElse(null);
if (hasMyAnnotation(element, MyAnnotation.class)) {
LOGGER.info(() ->"Skipping test");
return ConditionEvaluationResult.disabled(String.format("Skipped test: %s by #MyAnnotation", element));
}
return ConditionEvaluationResult.enabled("Test enabled");
}
private <T extends Annotation> boolean hasMyAnnotation(final AnnotatedElement element, Class<T> annotation) {
return element != null && AnnotationUtils.findAnnotation(element, annotation).isPresent();
}
}
Registring extenssion:
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
#ExtendWith(SkipConditionExtension.class)
public class TestObject {
#Test
public void test1() {
}
#Test
#MyAnnotation
public void test2() {
}
}
Output:
INFO: Skipping test
Skipped test: public void com.test.TestObject.test2() by #MyAnnotation
Solution 2, Skip test via invocation interseptor
InvocationInterceptor iterface defines the API for Extensions that wish to intercept calls to test.
Current implementation will behave exactly like your previous Rule.
Extension implementation:
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.InvocationInterceptor;
import org.junit.jupiter.api.extension.ReflectiveInvocationContext;
import org.junit.platform.commons.logging.Logger;
import org.junit.platform.commons.logging.LoggerFactory;
import org.junit.platform.commons.util.AnnotationUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
public class SkipCondition implements InvocationInterceptor {
private static final Logger LOGGER = LoggerFactory.getLogger(SkipConditionExtension.class);
#Override
public void interceptTestMethod(Invocation<Void> invocation, ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {
AnnotatedElement element = extensionContext.getElement().orElse(null);
if (hasMyAnnotation(element, MyAnnotation.class)) {
LOGGER.info(() ->"Skipping test");
invocation.skip();
} else {
invocation.proceed();
}
}
private <T extends Annotation> boolean hasMyAnnotation(final AnnotatedElement element, Class<T> annotation) {
return element != null && AnnotationUtils.findAnnotation(element, annotation).isPresent();
}
}
Registring extenssion:
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
#ExtendWith(SkipCondition.class)
public class TestObject {
#Test
public void test1() {
}
#Test
#MyAnnotation
public void test2() {
}
}
Please note, you can perform automatic extension registration according to documentation.

How to override the call (junit5)?

I can’t figure out how I can block the call to the B setTitle method so that it does nothing, but for example just output to the console (output from the system)?
In method B setTitle an error appears, but I want the tests to be independent and the error to be in the class with the test for B
#Component
class B {
public setTitle(String s){
...
}
}
#Service
class A {
#Autowired
private B b;
public getTitle(String s){
b.setTitle(s);
}
}
class ATest {
#Autowired
private class A;
#Test
void getTitleTest() {
//TODO how to override the call class B getTitle
}
}
First off, note that there is a lot of issues with what you have posted here.
You have methods declared without return types, getters that perform mutations, and trying to Autowire private class.
To answer your question, what you want to do is create a Mock and run this with a MockRunner.
Here is a test that will verify the method in your class B was invoked as you expected.
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
#RunWith(MockitoJUnitRunner.class)
public class ATest {
#Mock
private B b;
#InjectMocks
private A a;
#Test
public void getTitleTest() {
a.getTitle("soemthing");
Mockito.verify(b).setTitle("soemthing");
}
}
If you indeed want it to print something to the console, you can change the test method by capturing the argument to the method and simply printing it out, like this:
#Test
public void titleTester() {
ArgumentCaptor<String> stringArgumentCaptor = ArgumentCaptor.forClass(String.class);
doNothing().when(b).setTitle(stringArgumentCaptor.capture());
a.getTitle("soemthing");
System.out.println(stringArgumentCaptor.getValue());
}

How to test java class having initialisation in constructor

I have a java class whose constructor looks like this
private SomeManager someManager;
public MyService() {
this.someManager = ManagerHandler.getDefault();
}
The issue is that while testing ManagerHandler is not initialised so I am not able to create new object of this class to test its method. I am using mockito for testing. I am not able to understand How to mock a parameter which I am not passing in the constructor.
Is there anyway I can mock someManager using PowerMock?
You can use InjectMocks annotation. See below example:
MyService class:
public class MyService {
ManagerHandler someManager;
public MyService() {
this.someManager = ManagerHandler.getDefault();
}
// other methods
public String greetUser(String user) {
return someManager.sayHello(user) + ", Good Morning!";
}
}
ManagerHandler class:
public class ManagerHandler {
public static ManagerHandler getDefault() {
return new ManagerHandler();
}
public String sayHello(String userName) {
return "Hello " + userName;
}
}
TestClass:
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
#RunWith(MockitoJUnitRunner.class)
public class TestClass {
#Mock
ManagerHandler someManager;
#InjectMocks
MyService myService = new MyService();
#Test
public void test() {
//mock methods of ManagerHandler
Mockito.when(someManager.sayHello("Alice")).thenReturn("Hello Alice");
assertEquals("Hello Alice, Good Morning!", myService.greetUser("Alice"));
}
}

Change value of guice instance on runtime

I´m using google guice to inject this class example
class A {
String a;
}
Then is injected in my class B
class B {
#Inject A aInstance;
public void checkValue(){
System.out.println(aInstance.a);
}
}
Maybe using aspectJ, but what I would like is, that one test of mine, would get this A instance and would set the "a" string as "foo", before execute the test that cover the B class, so when the B class invoke checkValue this one would print "foo"
You mention the word test in your question - if you are writing a jUnit test for B you could perform the injection in an #Before clause, as demonstrated here.
private Injector injector;
#Before
public void init() throws Exception {
injector = Guice.createInjector(new AbstractModule() {
#Override
protected void configure() {
bind(A.class).to(MockedInstanceOfAWithValueFoo.class);
}
});
}
You could also call
bind(A.class).toInstance(new MockedInstanceOfAWithValueFoo());
If we assume that A has a constructor by which we can define A.a, the mocked instance could look like this:
public class MockedInstanceOfAWithValueFoo extends A{
public MockedInstanceOfAWithValueFoo() {
super("foo");
}
}
Again, you could make your mocked class accept the value of A.a through a constructor to make the creation of B (and the associated value of A.a) more dynamic.
With Mockito:
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.when;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
public class MyTest {
#Mock
A mockA;
#InjectMocks
B mockB;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
mockA.a = "Foo";
//when(mockA.getA()).thenReturn("Foo"); //if you use getter
}
#Test
public void myTest() {
assertNotNull(mockA);
assertNotNull(mockA.a);
assertNotNull(mockB);
assertNotNull(mockB.ainstance);
mockB.checkValue();
}
}

JSF Backing Bean Unit Test

I have a backing bean called e.g. PeopleListBean. Purpose is simple: return a list of people from a repository.
public class PeopleListBean {
#Autowired
private PersonRepository personRepository;
private List<Person> people;
#PostConstruct
private void initializeBean() {
this.people = loadPeople();
}
public List<User> getPeople() {
return this.people;
}
private List<Person> loadPeople() {
return personRepository.getPeople();
}
}
I want to create a unit test for this bean, using Junit and Mockito.
Example test class below:
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.example.PersonRepository;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:/test-application-context.xml" })
public class PeopleListBeanTest {
#Autowired
private PeopleListBean peopleListBean;
#Autowired
private PersonRepository mockPersonRepository;
#Before
public void init() {
reset(mockPersonRepository);
}
#Test
public void canListPeople() {
List<Person> people = getDummyList();
when(mockPersonRepository.getPeople().thenReturn(people);
assertTrue(peopleListBean.getPeople().size() == people.size());
}
}
My issue is, when/how to mock the repository since the loading takes place in the initializeBean method (#PostConstruct). So after the class is constructed, the "getPeople" method is called before I can actually mock the method resulting in an assertion mismatch.
I'd really appreciate some help/guidance!
Use JUnit's #BeforeClass annotation
Your code would therefore look as follows:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:/test-application-context.xml" })
public class PeopleListBeanTest {
#Autowired
private PeopleListBean peopleListBean;
#Autowired
private PersonRepository mockPersonRepository;
#BeforeClass
public static void initialise() {
}
// .
// .
// .
}

Categories