#InjectMocks #Autowired together issue - java

could you help me please,
some code:
#ContextConfiguration(locations = { "/applicationContext.xml" })
#RunWith(SpringJUnit4ClassRunner.class)
public class TestUnit2 {
#Mock
private MongoOperations mongoTemplate;
#InjectMocks
#Autowired
private WorkcircleRepositoryMongoImpl workCircleRepository;
#Autowired
private WorkcircleServiceImpl workCircleServiceImpl;
#Before
public void setUp() {
....
when(mongoTemplate.findOne(new Query(), Person.class)).thenReturn(expectedPerson);
MockitoAnnotations.initMocks(this);
}
#Test
public void test() {
... workCircleServiceImpl.find()...
}
But test is failed:
NP in "... workCircleServiceImpl.find()..." line,
in separate way #InjectMocks & #Autowired work, but together are not worked.

Usually when you are unit testing, you shouldn't initialize Spring context.
So remove Autowiring.
Usually when you do integration testing, you should use real dependencies.
So remove mocking.
You are mixing integration and unit test here.

Related

Different annotations for unit tests in Spring app

I am writing some unit tests and I am confused due to the different annotations in unit tests:
One of them is like:
#ExtendWith(SpringExtension.class)
class EmployeeServiceImplTest {
#MockBean
private EmployeeRepository employeeRepository;
#Autowired
private EmployeeServiceImpl employeeService;
#Test
void testFindAll() {
//...
}
//...
}
And another is using the following annotations:
#RunWith(MockitoJUnitRunner.class)
public class EmployeeServiceImplTest {
#Mock
private EmployeeRepository employeeRepository;
#InjectMocks
private EmployeeServiceImpl employeeService;
#Test
void testFindAll() {
//...
}
//...
}
So, I use Java and Spring Boot for language and framework. So, which annotations should I use?
#ExtendWith(SpringExtension.class) or #RunWith(MockitoJUnitRunner.class),
#MockBean or #Mock,
#Autowired or #InjectMocks
Any idea regarding to these annotations?

Is there a simple reason for why Mock and SpyBean can't be used together?

Initially, I had annotated a repository with #SpyBean, to track the number of times its methods were called. Then I realized I needed to annotate it with #Mock in order to mock what was returned from the repository.
So I ended up with:
...
#SpyBean
#Mock
SomeService someservice;
...
which caused all my tests using that service to fail with
java.lang.IllegalStateException: Failed to load ApplicationContext
So I removed #SpyBean and then everything worked again, except the reason I wanted to use #SpyBean was so that I could mock some methods and not others. Does that not work with #Mock?
Edit: someone asked for the file
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {RestApplication.class }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#ActiveProfiles({ "test" })
public class SomeServiceTest {
#Autowired
SomeService someService;
//#SpyBean
#Mock
SomeRepository someRepository;
String FILENAME = "txt";
#Before
public void setUp() {
someService = new SomeService(someRepository);
}
#Test
public void testFileName() {
when(someRepository.findSomethingByAttribute(anyString()))
.thenReturn(new SomePOJO("", FILENAME, ""));
someService.runFileName(FILENAME);
verify(someRepository, times(1)).save(any(SomePOJO.class));
}

How to write junit test cases for rest controller, service and dao layer using springboot?

How to write JUnit Test cases for RestController, Service and DAO layer?
I've tried MockMvc
#RunWith(SpringRunner.class)
public class EmployeeControllerTest {
private MockMvc mockMvc;
private static List<Employee> employeeList;
#InjectMocks
EmployeeController employeeController;
#Mock
EmployeeRepository employeeRepository;
#Test
public void testGetAllEmployees() throws Exception {
Mockito.when(employeeRepository.findAll()).thenReturn(employeeList);
assertNotNull(employeeController.getAllEmployees());
mockMvc.perform(MockMvcRequestBuilders.get("/api/v1/employees"))
.andExpect(MockMvcResultMatchers.status().isOk());
}
How can I verify the CRUD methods inside the rest controller and other layers ?
You can use #RunWith(MockitoJUnitRunner.class) for unit testing with your Service Layer mocking your DAO Layer components. You don't need SpringRunner.class for it.
Complete source code
#RunWith(MockitoJUnitRunner.class)
public class GatewayServiceImplTest {
#Mock
private GatewayRepository gatewayRepository;
#InjectMocks
private GatewayServiceImpl gatewayService;
#Test
public void create() {
val gateway = GatewayFactory.create(10);
when(gatewayRepository.save(gateway)).thenReturn(gateway);
gatewayService.create(gateway);
}
}
You can use #DataJpaTest for integration testing with
your DAO Layer
#RunWith(SpringRunner.class)
#DataJpaTest
public class GatewayRepositoryIntegrationTest {
#Autowired
private TestEntityManager entityManager;
#Autowired
private GatewayRepository gatewayRepository;
// write test cases here
}
Check this article for getting more details about testing with Spring Boot

Integration test for DB H2 and for controller

I have two integration test in my program and unfortunately both doesn't work. I don't know this is good idea to write both problem in one case but i try.
Firstly i show my db integration test :
#RunWith(SpringRunner.class)
#DataJpaTest
public class TeamDatabaseIntegrationTest {
#MockBean
private TeamRepository teamRepository;
#Autowired
private TestEntityManager testEntityManager;
#Test
public void testDb() {
Team team = new Team(1L, "teamName", "teamDescription", "krakow", 7);
Team team2 = new Team(2L, "teamName", "teamDescription", "krakow", 7);
testEntityManager.persist(team);
testEntityManager.flush();
Iterable<Team> teams = teamRepository.findAll();
assertThat(teams).hasSize(2).contains(team, team2);
}
In this test i add 2 elements to my db and expect that this test is ok but it return this :
java.lang.AssertionError:
Expected size:<2> but was:<0> in:
<[]>
In my second test i want to test controller method show all elements.
This is my method in cotroller:
#GetMapping("/teams")
public List<TeamDto> findAll() {
return teamService.findAll();
}
My test method for this look like this :
#SpringJUnitWebConfig(classes = CrewApplication.class)
public class TeamControllerMethodIntegrationTest {
private MockMvc mockMvc;
#Autowired
private WebApplicationContext webApplicationContext;
#Before
public void setup() throws Exception
{
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext).build();
MockitoAnnotations.initMocks(this);
}
#Test
void getAccount() throws Exception {
this.mockMvc.perform(get("/teams")
.accept(MediaType.parseMediaType("application/json;charset=UTF-8")))
.andExpect(status().isOk())
.andExpect(content().contentType("application/json;charset=UTF-8"))
.andExpect(jsonPath("$version").value(null))
.andExpect(jsonPath("$name").value("Apacze"))
.andExpect(jsonPath("$createOn").value(null))
.andExpect(jsonPath("modifiedOn").value(null))
.andExpect(jsonPath("$description").value("grupa programistow"))
.andExpect(jsonPath("$city").value("Włocławek"))
.andExpect(jsonPath("$headcount").value(null));
}
}
In this case i have other error.
java.lang.NullPointerException
at com.softwaremind.crew.people.integrationTest.TeamControllerMethodIntegrationTest.getAccount
I fight with this tests over week and i really have no idea how to repair this.
In your first case replace
#MockBean
private TeamRepository teamRepository;
with
#Autowired
private TeamRepository teamRepository;
(you cannot use mock and expect it to return values from in memory db)
For you second test. Remove #SpringJUnitWebConfig and annotate it with
#RunWith(SpringRunner.class)
#WebMvcTest()
and add Autowired to MockMvc
#Autowired
private MockMvc mockMvc;
EDIT
Additionally remove your setup() method as everything should be already configured. (and then you also don't need webApplicationContext attribute) and assert that the Test annotation you are using is org.junit.Test (check your imports)

Injecting mocks with Mockito does not work

I'm using Mockito to test my Spring project, but the #InjectMocks seems not working in injecting a mocked service into another Spring service(bean).
Here is my Spring service that I want to test:
#Service
public class CreateMailboxService {
#Autowired UserInfoService mUserInfoService; // this should be mocked
#Autowired LogicService mLogicService; // this should be autowired by Spring
public void createMailbox() {
// do mething
System.out.println("test 2: " + mUserInfoService.getData());
}
}
And below is the service that I want to mock:
#Service
public class UserInfoService {
public String getData() {
return "original text";
}
}
My test code is here:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "file:src/main/webapp/WEB-INF/spring/root-context.xml" })
public class CreateMailboxServiceMockTest {
#Mock
UserInfoService mUserInfoService;
#InjectMocks
#Autowired
CreateMailboxService mCreateMailboxService;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void deleteWithPermission() {
when(mUserInfoService.getData()).thenReturn("mocked text");
System.out.println("test 1: " + mUserInfoService.getData());
mCreateMailboxService.createMailbox();
}
}
but the result would like
test 1: mocked text
test 2: original text // I want this be "mocked text", too
it seems that the CreateMailboxService didn't get the mocked UserInfoService but using Spring's autowired bean.
Why is my #InjectMocks not working?
In my case, I had a similar issue when I worked with JUnit5
#ExtendWith(MockitoExtension.class)
class MyServiceTest {
...
#InjectMocks
MyService underTest;
#Test
void myMethodTest() {
...
}
underTest was null.
The cause of the problem was that I used #Test from JUnit4 package import org.junit.Test; instead JUnit5 import org.junit.jupiter.api.Test;
For those who stumbles on this thread and are running with JUnit 5 you need to replace
#RunWith(SpringJUnit4ClassRunner.class)
with
#ExtendWith(MockitoExtension.class)
#RunWith(JUnitPlatform.class)
Further reading here. Unfortunately there is no hint when executing the test cases with JUnit 5 using the old annotation.
You can create package level setter for mUserInfoService in CreateMailboxService class.
#Service
public class CreateMailboxService {
#Autowired UserInfoService mUserInfoService; // this should be mocked
#Autowired LogicService mLogicService; // this should be autowired by Spring
public void createMailbox() {
// do mething
System.out.println("test 2: " + mUserInfoService.getData());
}
void setUserInfoService(UserInfoService mUserInfoService) {
this.mUserInfoService = mUserInfoService;
}
}
Then, you can inject that mock in the test using the setter.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "file:src/main/webapp/WEB-INF/spring/root-context.xml" })
public class CreateMailboxServiceMockTest {
#Mock
UserInfoService mUserInfoService;
CreateMailboxService mCreateMailboxService;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
mCreateMailboxService = new CreateMailboxService();
mCreateMailboxService.setUserInfoService(mUserInfoService);
}
...
}
This way you can avoid problems with #InjectMocks and Spring annotations.
If you are trying to use the #Mock annotation for a test that relies directly on Spring injection, you may need to replace #Mock with #MockBean #Inject (both annotations), and #InjectMocks with #Inject. Using your example:
#MockBean
#Inject
UserInfoService mUserInfoService;
#Inject
CreateMailboxService mCreateMailboxService;
I had a pretty similar situation. I am writing it down just in case any reader is going through the same. In my case I found that the problem was that I was setting my injected variable as final in the local class.
Following your example, I had things like this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "file:src/main/webapp/WEB-INF/spring/root-context.xml" })
public class CreateMailboxServiceMockTest {
#Mock
UserInfoService mUserInfoService;
#InjectMocks
CreateMailboxService mCreateMailboxService = new CreateMailboxService(mUserInfoService);
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void deleteWithPermission() {
...
}
}
But in this class I had it like this:
#Service
public class CreateMailboxService {
private final UserInfoService mUserInfoService; // it is NOT injecting Mocks just because it is final! (all ok with private)
private final LogicService mLogicService; // it is NOT injecting Mocks just because it is final! (all ok with private)
#Autowired
public CreateMailboxService(UserInfoService mUserInfoService, LogicService mLogicService) {
this.mUserInfoService = mUserInfoService;
this.mLogicService = mLogicService;
}
public void createMailbox() {
...
}
}
Just deleting the final condition, #InjectMocks problem was solved.
For those who are running with JUnit 5 you need to replace the #RunWith(SpringJUnit4ClassRunner.class) with #ExtendWith(MockitoExtension.class).
For further reading take a look here.
there is no need of #Autowired annotation when you inject in the test class. And use the mock for the method to get your mocked response as the way you did for UserInfoService.That will be something like below.
Mockito.when(mCreateMailboxService. getData()).thenReturn("my response");
You can use MockitoJUnitRunner to mock in unit tests.
Use #Mock annotations over classes whose behavior you want to mock.
Use #InjectMocks over the class you are testing.
Its a bad practice to use new and initialize classes (better to go for dependency injection) or to introduce setters for your injections. Using setter injection to set dependencies only for tests is wrong as production code should never be altered for tests.
#RunWith(MockitoJUnitRunner.class)
public class CreateMailboxServiceMockTest {
#Mock
UserInfoService mUserInfoService;
#InjectMocks
CreateMailboxService mCreateMailboxService;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
...
}

Categories

Resources