This is my class and its constructor and the dependencies.
public class FavouriteProfilesController extends BaseController implements CurrentUser, JsonHelper {
private final UserProvider userProvider;
private MessagesApi msg;
#javax.inject.Inject
public FavouriteProfilesController(
UserProvider userProvider,
MessagesApi msgApi) {
this.userProvider = userProvider;
this.msg = msgApi;
}
// methods etc...
This is the test code I just copied from the docs:
public class FavouriteProfilesControllerTest extends WithApplication {
#Override
protected Application provideApplication() {
return new GuiceApplicationBuilder()
.configure("play.http.router", "javaguide.tests.Routes")
.build();
}
#Test
public void testIndex() {
Result result = new FavouriteProfilesController().index(); // Inject dependencies here
assertEquals(OK, result.status());
assertEquals("text/html", result.contentType().get());
assertEquals("utf-8", result.charset().get());
assertTrue(contentAsString(result).contains("Welcome"));
}
}
The controller has 2 dependencies, UserProvider and MessagesApi, how do I inject/mock them into the controller test?
If you use Mockito, you can mock them like this:
#RunWith(MockitoJUnitRunner.class)
public class FavouriteProfilesControllerTest extends WithApplication {
#InjectMocks
private FavouriteProfilesController controller;
#Mock
private UserProvider userProvider;
#Mock
private MessagesApi msg;
#Test
public void test() {
Assert.assertNotNull(userProvider);
Assert.asserNotNull(msg);
}
}
The solution depends on what you intend to test. If you mean to mock the whole behavior of UserProvider and MessageApi, using Mockito may be a proper solution.
In case you want to test controller functionality with real objects, you need to inject real objects. This may be done like this:
public class FavouriteProfilesControllerTest extends WithApplication {
#Test
public void testIndex() {
running(Helpers.fakeApplication(), () -> {
RequestBuilder mockActionRequest = Helpers.fakeRequest(
controllers.routes.FavouriteProfilesController.index());
Result result = Helpers.route(mockActionRequest);
assertEquals(OK, result.status());
assertEquals("text/html", result.contentType().get());
assertEquals("utf-8", result.charset().get());
assertTrue(contentAsString(result).contains("Welcome"));
});
}
}
Using of GuiceApplicationBuilder is not necessary, if you do not mean to use different injection binding for your test. Call to Helpers.fakeApplication() invokes the default dependency injection.
You can find more about unit testing in Play here.
Related
I have a test utility for with I need to have a fresh instance per test method (to prevent that state leaks between tests). So far, I was using the scope "prototype", but now I want to be able to wire the utility into another test utility, and the wired instances shall be the same per test.
This appears to be a standard problem, so I was wondering if there is a "test method" scope or something similar?
This is the structure of the test class and test utilities:
#RunWith(SpringRunner.class)
#SpringBootTest
public class MyTest {
#Autowired
private TestDriver driver;
#Autowired
private TestStateProvider state;
// ... state
// ... methods
}
#Component
#Scope("prototype") // not right because MyTest and TestStateProvider get separate instances
public class TestDriver {
// ...
}
#Component
public class TestStateProvider {
#Autowired
private TestDriver driver;
// ...
}
I'm aware that I could use #Scope("singleton") and #DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD) but this refreshes more than I need – a new TestDriver instance for each test would be enough. Also, this approach is error-prone because all tests using the TestDriver would need to know that they also need the #DirtiesContext annotation. So I'm looking for a better solution.
It is actually pretty easy to implement a testMethod scope:
public class TestMethodScope implements Scope {
public static final String NAME = "testMethod";
private Map<String, Object> scopedObjects = new HashMap<>();
private Map<String, Runnable> destructionCallbacks = new HashMap<>();
#Override
public Object get(String name, ObjectFactory<?> objectFactory) {
if (!scopedObjects.containsKey(name)) {
scopedObjects.put(name, objectFactory.getObject());
}
return scopedObjects.get(name);
}
#Override
public void registerDestructionCallback(String name, Runnable callback) {
destructionCallbacks.put(name, callback);
}
#Override
public Object remove(String name) {
throw new UnsupportedOperationException();
}
#Override
public String getConversationId() {
return null;
}
#Override
public Object resolveContextualObject(String key) {
return null;
}
public static class TestExecutionListener implements org.springframework.test.context.TestExecutionListener {
#Override
public void afterTestMethod(TestContext testContext) throws Exception {
ConfigurableApplicationContext applicationContext = (ConfigurableApplicationContext) testContext
.getApplicationContext();
TestMethodScope scope = (TestMethodScope) applicationContext.getBeanFactory().getRegisteredScope(NAME);
scope.destructionCallbacks.values().forEach(callback -> callback.run());
scope.destructionCallbacks.clear();
scope.scopedObjects.clear();
}
}
#Component
public static class ScopeRegistration implements BeanFactoryPostProcessor {
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException {
factory.registerScope(NAME, new TestMethodScope());
}
}
}
Just register the test execution listener, and there will be one instance per test of all #Scope("testMethod") annotated types:
#RunWith(SpringRunner.class)
#SpringBootTest
#TestExecutionListeners(listeners = TestMethodScope.TestExecutionListener.class,
mergeMode = MergeMode.MERGE_WITH_DEFAULTS)
public class MyTest {
#Autowired
// ... types annotated with #Scope("testMethod")
}
I ran into the same problem some time ago and came to this solution:
Use Mocks
I wrote some methods to create specific mockito settings to add behavior to each mock.
So create a TestConfiguration class with following methods and bean definition.
private MockSettings createResetAfterMockSettings() {
return MockReset.withSettings(MockReset.AFTER);
}
private <T> T mockClass(Class<T> classToMock) {
return mock(classToMock, createResetAfterMockSettings());
}
and your bean definition will look like:
#Bean
public TestDriver testDriver() {
return mockClass(TestDriver .class);
}
MockReset.AFTER is used to reset the mock after the test method is run.
And finally add a TestExecutionListeners to your Test class:
#TestExecutionListeners({ResetMocksTestExecutionListener.class})
My FixValueConceptIntegration class has a constructor and it looks like this:
private ReferenceConceptHelper referenceConceptHelper;
private ConceptClientFacade conceptClientExternalFacade;
public FixValueConceptIntegration()
{
referenceConceptHelper = JournalSingletonFactory.getInstance().getSingletonInstance(ReferenceConceptHelper.class);
conceptClientExternalFacade = JournalSingletonFactory.getInstance().getSingletonInstance(ConceptClientFacade.class);
}
So now I'm going to test it using Mockito.
If we have a constructor like
public FixValueConceptIntegration(ReferenceConceptHelper referenceConceptHelper, ConceptClientFacade conceptClientExternalFacade)
{
this.referenceConceptHelper = referenceConceptHelper
this.conceptClientExternalFacade = conceptClientExternalFacade
}
I know it is easy to initialize when we are going to testing the class. Because we can just mock the ReferenceConceptHelper and ConceptClientFacade classes.
Then we can use it at the #BeforeMethod like this:
#BeforeMethod
public void beforeMethod()
{
MockitoAnnotations.initMocks(this);
fixValueConceptIntegration = new FixValueConceptIntegration(referenceConceptHelper, conceptClientExternalFacade);
}
Then all the dependencies will inject to the constructor and no worries.
So here the problem is I can't figure out how to inject these dependencies (by mocking) to the above testable class.
Just use the mock (org.mockito.Mockito.mock) method for the class and the when method to mock the method calls:
#Test
public void yourTest() {
ReferenceConceptHelper referenceConceptHelper = mock(ReferenceConceptHelper .class);
when(referenceConceptHelper.someMethod(any()).thenReturn("hello");
ConceptClientFacade conceptClientExternalFacade = mock(ConceptClientExternalFacade.class);
when(conceptClientExternalFacade.someMethod(any()).thenReturn("world");
FixValueConceptIntegration integration = new FixValueConceptIntegration(referenceConceptHelper, conceptClientExternalFacade);
assertEquals("hello world", integration.methodThatYouWouldLikeToTest());
}
In this case, you do not need to use the #BeforeMethod or call MockitoAnnotations.initMocks(this);. For unit tests, the initMocks are only useful if you do not have access directly to the class injected (typically when you are using field injection).
But if you would like to use the annotations (I personally don't like), you can do something like that:
#InjectMocks
private FixValueConceptIntegration integration;
#Mock
private ReferenceConceptHelper referenceConceptHelper;
#Mock
private ConceptClientFacade conceptClientFacade;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
when(referenceConceptHelper.someMethod(any()).thenReturn("hello");
when(conceptClientExternalFacade.someMethod(any()).thenReturn("world");
}
#Test
public void yourTest() {
assertEquals("hello world", integration.methodThatYouWouldLikeToTest());
}
I extended my test class with TestNGBase which extends PowerMockTestCase.
And then add registerMockSingleton method to the TestNGBase class like this;
protected <E, I extends E> void registerMockSingleton(Class<E> typeInterface, I mock)
{
delegate.registerMockSingleton(typeInterface, mock);
}
Then inject mock dependencies to the constructor like this way;
#Override
public void performSetup() {
MockitoAnnotations.initMocks(this);
registerMockSingleton(ReferenceConceptHelper.class,mockReferenceConceptHelper);
registerMockSingleton(ConceptClientFacade.class,mockConceptClientExternalFacade);
fixValueConceptIntegration = new FixValueConceptIntegration();
}
#Override
protected void performTearDown() throws Exception
{
fixValueConceptIntegration = null;
}
All solved!!!
(My testable class constructor doesn't inject dependencies to with constructor
arguments.Thats why I solved my problem like this)
I have class A which is taking a set as guice dependency. The set is singleton. Below is the code example:
class A
{
private Set<InetAddress> set;
private String pingUriPath;
#Inject
public A(Set<InetAddress> set, #Named("pingUri") String pingUriPath)
{
this.set = set;
this.pingUriPath = pingUriPath; // this is used somewhere
}
public void storeValue(String str)
{
if(str.equals("abc"))
{
set.add(str);
}
}
}
Here is the guice module that injects dependency:
private class GuiceModule extends AbstractModule {
#Override
public void configure() {
bindConstant().annotatedWith(Names.named("pingUri")).to("/ping");
}
#Provides
#Singleton
Set<InetAddress> healthyTargets(){
return Sets.newConcurrentHashSet();
}
}
I want to mock the method storeValue and for that i have to mock the set. I am not able to mock the set using guice.
If i mock like below, it gives assertion error(no interactions with this mock)
#Mock
Set<InetAddress> mockHealthyTargets;
private class MockClassesModule extends AbstractModule {
#Override
public void configure() {
bindConstant().annotatedWith(Names.named("pingUri")).to("/ping");
}
#Provides
#Singleton
Set<InetAddress> healthyTargets(){
return Sets.newConcurrentHashSet();
}
}
public test_storeValue()
{
Injector injector = Guice.createInjector(new MockClassesModule());
A a = injector.getInstance(A.class);
a.storeValue("abc");
verify(mockHealthyTargets).add("abc")
}
If you have the need to use guice in your unit tests, something is most likely going the wrong direction. One of the biggest benefits of dependency injection is that testing becomes easy, because you can pass dependencies that are controlled by you.
I assume you want to test the class A and specifically the method storeValue. For this you don't even need mocking
#Test
public void test() {
// prepare dependencies
Set<InetAddress> set = Sets.newConcurrentHashSet();
String pingUri = "example.com";
// prepare input
String input = "someValue";
// prepare class under test
A classUnderTest = new A(set, pingUri);
// call class under test
classUnderTest.storeValue(input);
// check that what you expected happened
// in this case you expect that the dependency set now contains the input
assertThat(set, contains(input));
}
I have found what the mistake was, I should return mock when providing to my unit test. It should look like this:
#Mock
Set<InetAddress> mockHealthyTargets;
private class MockClassesModule extends AbstractModule {
#Override
public void configure() {
bindConstant().annotatedWith(Names.named("pingUri")).to("/ping");
}
#Provides
#Singleton
Set<InetAddress> healthyTargets(){
return mockHealthyTargets;
}
}
I want to replace an autowired class of a service in my spring boot app with a mocked implementation of that class that I created specifically for testing.
I chose to create this mocked implementation because the behaviour of this class is too complicated to mock using mockito as it requires multiple other mocks itself.
I am not able to work out how to inject this mocked implementation into the service.
Here is a minimal example of the situation:
#Service
public class ServiceIWantToTestImpl implements ServiceIWantToTest{
#Autowired
ComplicatedDependency complicatedDependency;
#Override
public void methodUsingDependency(){
String string = complicatedDependency.doSomething();
System.out.println(string);
}
}
public class MockComplicatedDependency implements ComplicatedDepencency{
public MockComplicatedDependency(...){
// Inject other mocked objects into this mock
}
public String doSomthing(){
// This would be a mocked version of this function for testing
return "test";
}
}
#RunWith(MockitoJUnitRunner.class)
public class TestingTheService(){
#InjectMock
private static ServiceIWantToTest serviceIWantToTest = new ServiceIWantToTestImpl();
#Mock
ComplicatedDependency mockComplicatedDependency;
#BeforeClass
public static void init(){
mockComplicatedDependency = new MockComplicatedDependency(...);
}
#Test
public void testAttempt(){
serviceIWantToTest.methodUsingDependency(); // This method calls complicatedDependency.doSomething() which does not run the mocked version in MockComplicatedDependency which I wanted to inject, and would always return null instead of the "test" string I put in this example.
}
}
Do you have to use Mockito annotations to setup dependencies for the class under test?
If that is not the main constraint why not just do the plain simple setup and introduce a constructor or a setter in ServiceIWantToTestImpl class for the ComplicatedDependency field and set the dependency in your test setup directly to whatever impl of ComplicatedDependency you like e.g.:
#Service
public class ServiceIWantToTestImpl implements ServiceIWantToTest {
#Autowired
ComplicatedDependency complicatedDependency;
public ServiceIWantToTestImpl() {
}
public ServiceIWantToTestImpl(ComplicatedDependency complicatedDependency) {
this.complicatedDependency = complicatedDependency;
}
#Override
public void methodUsingDependency(){
String string = complicatedDependency.doSomething();
System.out.println(string);
}
}
public class TestingTheService {
private static ServiceIWantToTestImpl serviceIWantToTest;
#BeforeClass
public static void init(){
serviceIWantToTest = new ServiceIWantToTestImpl(new MockComplicatedDependency());
}
#Test
public void testAttempt() {
serviceIWantToTest.methodUsingDependency();
}
}
That is one way.
To make it work with Mockito, You could to use #Spy instead of #Mock like this:
#RunWith(MockitoJUnitRunner.class)
public class TestingTheService {
#InjectMocks
private static ServiceIWantToTestImpl serviceIWantToTest = new ServiceIWantToTestImpl();
#Spy
private static ComplicatedDependency complicatedDependency = new MockComplicatedDependency();
#BeforeClass
public static void init() {
}
#Test
public void testAttempt() {
serviceIWantToTest.methodUsingDependency();
}
}
Though this is a bit of a hack. I strongly recommend that you read the JavaDoc of the #Spy annotation and make sure it's expected use is what you really need for your test.
I'm new to JMockIt and am trying to figure out/understand how to use #Injectable for a top-level MockUp class that I have already defined.
For example:
// JUnit Test Class
public class RepositoryTest {
#Tested private Repository repository;
#Injectable private ResultsAPIWrapper resultsApiWrapper;
#Test
public void testRepo(){
new ResultsApiWrapper();
assertThat(repository.doSomething(), is("done" ) );
}
}
// Class under test
public class Repository{
#Autowired private ResultsAPIWrapper resultsApiWrapper;
public String doSomething(){
return resultsApiWrapper.load();
}
}
// Mocked implementation of the ResultsAPIWrapper that I want injected into Repository
public class ResultsApiWrapperMock extends MockUp<ResultsAPIWrapper>{
#Mock
public String load(){
return "done";
}
}
If I try the above, I get an error
java.lang.IllegalArgumentException: Class already mocked: com.fw.wrappers.ResultsAPIWrapper
at com.fw.wrappers.mock.ResultsApiWrapperMock.<init>(ResultsApiWrapperMock.java:12)
at com.fw.repository.RepositoryTest.testRepo(RepositoryTest.java:38)
But If I remove the new ResultsApiWrapper() then I do not know how to specify which is the class I want to use as my mocked implementation for the autowire.
Am I misunderstanding how to do this? How can I specify that I want JMockit to autowire using my MockUp<> implementation?
I'm new too but I think something like this would work in your case...
This will mock the ResultsAPIWrapper() and not initialize any static variables and create a specific mock for load():
new MockUp<ResultsAPIWrapper>() {
#Mock
void $clinit() {
//disable static initialization
}
#Mock
public String load() {
return "done";
}
};