I want to set up mock data using Mockito before my test. However, the autowire happens before the #Before so my tests that expect data to be present is missing. Is there a way around it?
#RunWith(SpringRunner.class)
#ContextConfiguration(
classes = {
Foo.class
}
)
public class FooTest {
#MockBean
final Programs programs;
#Autowired
final Foo foo;
#Before
public void setPrograms() {
when(programs.findAll())
.thenReturn(
List.of(
"A", "B", "C"
)
);
}
#Test
public void foo() {
assertThat(foo.getBlah()).isNotEmpty();
}
}
interface Programs {
List<String> findAll();
}
class Foo {
// I have more complicated structures than a list, for example only.
private List<String> blah;
#Autowired
private Programs programs;
public List<String> getBlah() { return blah; }
#PostConstruct
public void init() {
blah = programs.findAll();
}
}
Following your example I have developed the next ones:
public interface Programs {
List<String> findAll();
}
public class Foo {
// I have more complicated structures than a list, for example only.
private List<String> blah;
#Autowired
private Programs programs;
public List<String> getBlah() { return blah; }
#PostConstruct
public void init() {
blah = programs.findAll();
}
}
Above ones equals to your provided code. Now, "the changes":
// Only for testing purpose, you can use any of your own ones
public class ProgramsImpl implements Programs {
#Override
public List<String> findAll() {
return asList("1", "2", "3");
}
}
And the junit test:
#RunWith(SpringRunner.class)
#ContextConfiguration(
classes = {
Foo.class, ProgramsImpl.class
}
)
public class FooTest {
#SpyBean
Programs programs;
#Autowired
Foo foo;
#Before
public void prepare() {
when(programs.findAll())
.thenReturn(
List.of(
"A", "B", "C"
)
);
this.foo.init();
}
#Test
public void foo() {
assertEquals(asList("A", "B", "C"), foo.getBlah());
}
}
The above test works as expected, that is, although ProgramsImpl.findAll returns "1", "2", "3" the when clause included will overwrite it with your own one.
However, as you probably will figure out really the #PostConstruct is invoked twice: one due to #Autowire and the second one due to init.
If you want to avoid it, you need to remove #Autowire in your test and create your custom instance of foo inside #Before (using a "normal constructor"). For example:
public class Foo {
...
private Programs programs;
#Autowired
public Foo(Programs programs) {
this.programs = programs;
}
...
}
#RunWith(SpringRunner.class)
#ContextConfiguration(
classes = {
ProgramsImpl.class
}
)
public class FooTest {
#SpyBean
Programs programs;
Foo foo;
#Before
public void prepare() {
when(programs.findAll())
.thenReturn(
List.of(
"A", "B", "C"
)
);
this.foo = new Foo(programs);
this.foo.init();
}
#Test
public void foo() {
assertEquals(asList("A", "B", "C"), foo.getBlah());
}
}
As Programs is an interface; in reality it's extends CrudRepository I am able to instantiate a copy of it even a mock with a #Configuration/#Bean. This solution ensures that everything (except the mocks) are managed by Spring including the PostConstruct lifecycle.
This approach allows me to have Spring components that contain PostConstructs that use JPA without having to set up an initial database with the proper data.
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.PostConstruct;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
#RunWith(SpringRunner.class)
#ContextConfiguration(
classes = {
Foo.class,
StackOverflowTest.ProgramsConfiguration.class
}
)
public class StackOverflowTest {
#Autowired
private Foo foo;
#Configuration
static class ProgramsConfiguration {
#Bean
public Programs programs() {
final Programs mock = mock(Programs.class);
when(mock.findAll()).thenReturn(List.of("A", "B", "C"));
return mock;
}
}
#Test
public void foo() {
assertThat(foo.getBlah())
.isNotEmpty()
.containsExactly("A", "B", "C");
}
}
interface Programs {
List<String> findAll();
}
class Foo {
private List<String> blah;
#Autowired
private Programs programs;
public List<String> getBlah() {
return blah;
}
#PostConstruct
public void init() {
blah = programs.findAll();
}
}
I actually found that I had solved this problem a while back when I was trying to get JOOQ working with PostConstructs as well using a MockDslContextConfiguration. Took me a bit of time to realize it was the same situation.
#Configuration
public class MockDslContextConfiguration {
#Bean
public DSLContext dslContext() {
return DSL.using(new MockConnection(mockExecuteContext -> new MockResult[]{
new MockResult(0, Mockito.mock(Result.class)),
new MockResult(0, Mockito.mock(Result.class))
}), SQLDialect.MYSQL);
}
}
Though this Q&A is more general and not limited to JOOQ.
This has a limitation of that I can only have one set of data for the test per test class.
Related
I have a dummy project where I try figure out how to test pointcuts being triggered.
My project consists of 1 aspect bean which just prints after a foo method is called
#Component
#Aspect
public class SystemArchitecture {
#After("execution(* foo(..))")
public void after() {
System.out.println("#After");
}
}
And a FooServiceImpl with implemented foo method
#Service
public class FooServiceImpl implements FooService{
#Override
public FooDto foo(String msg) {
return new FooDto(msg);
}
}
The code works and and I can see "#After" being printed to console, but I can't check programatically if after pointcut was called using the test below.
#SpringBootTest
public class AspectTest {
#Autowired
private FooService fooService;
#Test
void shouldPass() {
fooService.foo("hello");
}
}
I've also tried using non-bean proxy as was adviced in https://stackoverflow.com/a/56312984/18224588, but this time I'm getting an obvious error cannot extend concrete aspect because my spy proxy is no longer viewed as an aspect:
public class AspectNoContextTest {
#Test
void shouldPass() {
FooService fooService = Mockito.mock(FooService.class);
SystemArchitecture systemArchitecture = Mockito.spy(new SystemArchitecture());
AspectJProxyFactory aspectJProxyFactory = new AspectJProxyFactory(fooService);
aspectJProxyFactory.addAspect(systemArchitecture);
DefaultAopProxyFactory proxyFactory = new DefaultAopProxyFactory();
AopProxy aopProxy = proxyFactory.createAopProxy(aspectJProxyFactory);
FooService proxy = (FooService) aopProxy.getProxy();
proxy.foo("foo");
verify(systemArchitecture, times(1)).after();
}
}
Ok, after some digging, I found that it's possible to accomplish this by making an aspect a #SpyBean. Also AopUtils can be used for performing additional checks
#SpringBootTest
public class AspectTest {
#Autowired
private FooService fooService;
#SpyBean
private SystemArchitecture systemArchitecture;
#Test
void shouldPass() {
assertTrue(AopUtils.isAopProxy(fooService));
assertTrue(AopUtils.isCglibProxy(fooService));
fooService.foo("foo");
verify(systemArchitecture, times(1)).after();
}
}
I have an interface without implementation classes.
public interface MyInterface {
String getName();
}
And I have another class which have MyInterface as dependency.
#Component
public class SomeClass {
#Autowired
private MyInterface implementation;
public MyInterface someMethod(List<MyInterface> list){
//logic
}
}
I have to test SomeClass, but I don't have MyInterface implementation classes. Is it possible to create in test few MyInterface implementation classes and add them to ApplicationContext when I can get them as spring beans with #Autowired?
Assuming you use JUnit 5, this is possible using #TestConfiguration and provide an implementation there:
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.test.context.junit.jupiter.SpringExtension;
#ExtendWith(SpringExtension.class)
class SomeServiceTest {
#Autowired
private MyInterface myInterface;
#TestConfiguration
static class TestConfig {
#Bean
public MyInterface myInterface() {
/**
* Long version of implementing your interface:
*
* return new MyInterface() {
* #Override
* public String getName() {
* return null;
* }
* };
*/
// shorter ;-)
return () -> "Hello World!";
}
}
#Test
void test() {
SomeService someService = new SomeService(myInterface);
System.out.println(someService.doFoo());
}
}
But you could also use Mockito and create a mock for your MyInterface and have a fast unit test:
#ExtendWith(MockitoExtension.class)
class SomeServiceTest {
#Mock
private MyInterface myInterface;
#InjectMocks
private SomeService someService;
#Test
void test() {
when(myInterface.getName()).thenReturn("Test");
System.out.println(someService.doFoo());
}
}
While the code above technically answers what you asked for, always consider, as J Asgarov mentioned in the comments, if it makes sense to do it in this way.
Trying to get JUnit with mockito testing to work and getting a NPE on my test here. I'm wanting to have a verify that when createRegistrant(registrationDTO) is called, saveUpdateRegistration(Registration reg) method is called right after. An issue I find strange is that on Mockito.verify(registrationServiceImpl, Mockito.times(1)).createRegistrant(registrationDTO); it is not suggesting I can test if saveUpdateRegistration(Registration reg) method was called? IntelliJ only suggests methods that are in my interface?
My test code below:
#RunWith(MockitoJUnitRunner.class)
public class RegistrationServiceImplTest {
#InjectMocks
private RegistrationServiceImpl registrationServiceImpl;
#Mock
private RegistrationDTO registrationDTO;
#Mock
private Registration registration;
#Before
public void setup() {
registrationDTO.seteId("abc123");
registrationDTO.setTech("AWS");
registrationDTO.setFirstName("Bob");
registrationDTO.setLastName("Tom");
}
#Test
public void createRegistrant() throws Exception {
// Mockito.when(registrationServiceImpl.createRegistrant(registrationDTO)).thenReturn(registrationDTO);
Mockito.when(registrationServiceImpl.createRegistrant(registrationDTO)).thenReturn(registrationDTO);
registrationServiceImpl.createRegistrant(registrationDTO);
Mockito.verify(registrationServiceImpl, Mockito.times(1)).createRegistrant(registrationDTO);
}
Here is the code I'm testing:
package com.TechODex.service;
import com.TechODex.dto.RegistrationDTO;
import com.TechODex.model.Registration;
import com.TechODex.dao.RegistrationDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
#Service
#Transactional
public class RegistrationServiceImpl implements RegistrationService {
#Autowired
private RegistrationDAO registrationDAO;
public RegistrationDTO createRegistrant(RegistrationDTO reg) {
saveUpdateRegistration(setDTOToModel(reg));
return reg;
}
public void deleteRegistrant(Long id) { deleteUserRegistrant(id); }
public List<Registration> findAllRegistrant(String tech) { return findAllRegistrantDAO(tech);}
public List<Registration> findAllTech() { return findAllTechDAO();}
private Registration setDTOToModel(RegistrationDTO dto){
Registration registration = new Registration();
registration.setFirstName(dto.getFirstName());
registration.setLastName(dto.getLastName());
registration.seteId(dto.geteId());
registration.setTech(dto.getTech());
return registration;
}
private void saveUpdateRegistration(Registration reg){ registrationDAO.save(reg);}
}
There are several issues here.
First, you do not mock RegistrationDAO. This will lead to it being null in the class under test. Next, RegistrationService is not a mock, yet you try to use when and verifyon it. Last, RegistrationDTO is mocked, so the invocations to the setters in #Before has no effect.
Your test should look something like:
#RunWith(MockitoJUnitRunner.class)
public class RegistrationServiceImplTest {
#InjectMocks
private RegistrationServiceImpl registrationServiceImpl;
#Mock
private RegistrationDAO registrationDAO;
private RegistrationDTO registrationDTO;
private Registration registration;
#Before
public void setup() {
registration = new Registration();
registration.seteId("abc123");
registration.setTech("AWS");
registration.setFirstName("Bob");
registration.setLastName("Tom");
registrationDTO = new RegistrationDTO();
registrationDTO.seteId("abc123");
registrationDTO.setTech("AWS");
registrationDTO.setFirstName("Bob");
registrationDTO.setLastName("Tom");
}
#Test
public void createRegistrant() throws Exception {
final RegistrationDTO result = registrationServiceImpl.createRegistrant(registrationDTO);
assertSame(registrationDTO, result);
verify(registrationDAO).save(eq(registration));
}
}
given that Registration has an implemented equals-method where the fields that are set are compared. If not, you need to use an ArgumentCaptor.
I am writing integration test case which is used to create and update a data
#RunWith(SpringRunner.class)
#SpringBootTest(classes = MyApplication.class, webEnvironment =
SpringBootTest.WebEnvironment.DEFINED_PORT)
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class MyIntegrationTest {
private String baseUrl="http://192.168.6.177/api/v1/";
#Autowired
TestRestTemplate restTemplate;
Long createdId; // trying to set ID which is coming after test1_AddData
#Test
public void test1_AddData() throws Exception {
ABC abc = new ABC("Name");
HttpEntity<ABC> requestBodyData = new HttpEntity<>(ABC);
ParameterizedTypeReference<RestTemplateResponseEnvelope<ABC>> typeReference =
new ParameterizedTypeReference<RestTemplateResponseEnvelope<ABC>>() {
};
ResponseEntity<RestTemplateResponseEnvelope<ABC>> response = restTemplate.exchange(
baseUrl + "/presenceType",
HttpMethod.POST, requestBodyData, typeReference);
Assert.assertTrue(HttpStatus.CREATED.equals(response.getStatusCode()));
createdId = response.getBody().getData().getId();
}
#Test
public void test2_updateData() throws Exception {
ABC abc = new ABC("NEW NAME");
System.out.println("------------------------------------------" + createdId); /// it is giving null
HttpEntity<ABC> requestBodyData = new HttpEntity<>(ABC);
ResponseEntity<ABC> response = restTemplate.exchange(
baseUrl + "/presenceType/" + createdId,
HttpMethod.PUT, requestBodyData, ABC.class);
Assert.assertTrue(HttpStatus.OK.equals(response.getStatusCode()));
createdId = response.getBody().getId();
}
}
the output of my execution
------------------------------------------null
What needs to be done to make this execution i.e calling of second function after the exection of first.
NOTE : The code also contains delete method which needs to be called after third.
Although it is not good practice to fix order in Tests. But If you are using JUnit above version 4.11, it has annotation #FixMethodOrder.
You can set order by method names.
Example:
import org.junit.runners.MethodSorters;
import org.junit.FixMethodOrder;
import org.junit.Test;
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class OrderTest {
#Test
public void test1() {
System.out.println("test1");
}
#Test
public void test2() {
System.out.println("test2");
}
}
For further reading #FixMethodOder
Junit Git Page: https://github.com/junit-team/junit4/wiki/test-execution-order
Custom Implemenation: https://memorynotfound.com/run-junit-tests-method-order/
FixMethodOrder not working for me, so I find another way to do this.
We can use #TestMethodOrder from Junit jupiter
https://junit.org/junit5/docs/5.5.0/api/org/junit/jupiter/api/TestMethodOrder.html
#Order annotation used to specify the sequence
Example code:
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
#TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class DummyTest1 {
#Test
#Order(2)
public void read(){
System.out.println("read");
}
#Test
#Order(4)
public void delete(){
System.out.println("delete");
}
#Test
#Order(1)
public void create(){
System.out.println("create");
}
#Test
#Order(3)
public void update(){
System.out.println("update");
}
}
It will execute in sequence order order1, order2, order3, order4
So testing order will be,
create
read
update
delete
I am new to jmockit and would like to mock a bean inside my Java based Spring Application Configuration. I thought (better hoped) it would go like this:
#Configuration
public class MyApplicationConfig {
#Bean // this bean should be a mock
SomeService getSomeService() {
return new MockUp<SomeService>() {#Mock String someMethod() { return ""; }}.getMockInstance();
}
#Bean // some other bean that depends on the mocked service bean
MyApplication getMyApplication(SomeService someService) {
....
}
}
But unfortunatly this fails with "Invalid place to apply a mock-up".
I wonder if I can generate jmockit mocks inside Spring Configuration classes at all. I need the bean because it is referenced by other beans and the whole Spring Context initialization fails if I do not provide the mock as a Spring bean.
Thanks for any help.
Just use your regular Spring configuration. In a test class, declare the type to be mocked with #Capturing. It will mock whatever the implementation class that Spring used.
Edit: added full example code below.
import javax.inject.*;
public final class MyApplication {
private final String name;
#Inject private SomeService someService;
public MyApplication(String name) { this.name = name; }
public String doSomething() {
String something = someService.doSomething();
return name + ' ' + something;
}
}
public final class SomeService {
public String getName() { return null; }
public String doSomething() { throw new RuntimeException(); }
}
import org.springframework.context.annotation.*;
#Configuration
public class MyRealApplicationConfig {
#Bean
SomeService getSomeService() { return new SomeService(); }
#Bean
MyApplication getMyApplication(SomeService someService) {
String someName = someService.getName();
return new MyApplication(someName);
}
}
import javax.inject.*;
import org.junit.*;
import org.junit.runner.*;
import static org.junit.Assert.*;
import mockit.*;
import org.springframework.test.context.*;
import org.springframework.test.context.junit4.*;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = MyRealApplicationConfig.class)
public final class MyApplicationSpringTest {
#Inject MyApplication myApplication;
#Mocked SomeService mockService;
#BeforeClass // runs before Spring configuration
public static void setUpMocksForSpringConfiguration() {
new MockUp<SomeService>() {
#Mock String getName() { return "one"; }
};
}
#Test
public void doSomethingUsingMockedService() {
new Expectations() {{ mockService.doSomething(); result = "two"; }};
String result = myApplication.doSomething();
assertEquals("one two", result);
}
}
import org.junit.*;
import static org.junit.Assert.*;
import mockit.*;
// A simpler version of the test; no Spring.
public final class MyApplicationTest {
#Tested MyApplication myApplication;
#Injectable String name = "one";
#Injectable SomeService mockService;
#Test
public void doSomethingUsingMockedService() {
new Expectations() {{ mockService.doSomething(); result = "two"; }};
String result = myApplication.doSomething();
assertEquals("one two", result);
}
}
Spring-ReInject is designed to replace beans with mocks.