Spring Boot Unit Test - java

I am new to spring boot. Need some suggestions
Here my unit test class
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = DemoApplication.class)
public class EmployeeRepositoryTest {
#Autowired
protected EmployeeRepository employeeRepository;
#Test
public void insertEmploee(){
Employee employee = new Employee();
employee.setEmpName("Azad");
employee.setEmpDesignation("Engg");
employee.setEmpSalary(12.5f);
employeeRepository.save(employee);
}
}
When I run it I get exception as
java.lang.NoSuchMethodError: org.springframework.core.annotation.AnnotatedElementUtils.findMergedAnnotationAttributes(Ljava/lang/reflect/AnnotatedElement;Ljava/lang/String;ZZ)Lorg/springframework/core/annotation/AnnotationAttributes;
at org.springframework.test.util.MetaAnnotationUtils$AnnotationDescriptor.<init>(MetaAnnotationUtils.java:290)
at org.springframework.test.util.MetaAnnotationUtils$UntypedAnnotationDescriptor.<init>(MetaAnnotationUtils.java:365)
at org.springframework.test.util.MetaAnnotationUtils$UntypedAnnotationDescriptor.<init>(MetaAnnotationUtils.java:360)
at org.springframework.test.util.MetaAnnotationUtils.findAnnotationDescriptorForTypes(MetaAnnotationUtils.java:191)
at org.springframework.test.util.MetaAnnotationUtils.findAnnotationDescriptorForTypes(MetaAnnotationUtils.java:198)
at
Process finished with exit code -1

It seems that your problem is solved (mixing the Spring dependency versions) but let me just expand the comment from #g00glen00b on how to write unit tests.
Make sure the following dependency is in your pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
As pointed out in the comment, #RunWith(SpringJUnit4ClassRunner.class) causes the unit test to start the whole application and it is used rather for integration testing.
Fortunately, Spring-boot has built in dependency for Mockito which is just what you need for unit tests like this.
Now, your unit test could look something like this:
public class EmployeeRepositoryTest {
#InjectMocks
private EmployeeRepository employeeRepository;
#Mock
private Something something; // some class that is used inside EmployRepository (if any) and needs to be injected
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
#Test
public void insertEmploee(){
Employee employee = new Employee();
employee.setEmpName("Azad");
employee.setEmpDesignation("Engg");
employee.setEmpSalary(12.5f);
employeeRepository.save(employee);
Mockito.verify(...); // verify what needs to be verified
}
}
Nice post about using Mockito can be found, for example, here.

Instead of using #Autowired on EmployeeRepository we can use #MockBean cause we are writing unit tests we don't need to deal with the real data we just need to verify that the function is working fine or not. Check the below code
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(classes = Main.class)//main springboot class
#WebAppConfiguration
public abstract class AbstractBaseTest {
protected MockMvc mvc;
#Autowired
WebApplicationContext webApplicationContext;
protected void setUp() {
mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
}
public class EmployeeRepositoryTest extends AbstractBaseTest{
#MockBean
protected EmployeeRepository employeeRepository;
#Override
#Before
public void setUp() {
super.setUp();
}
#Test
public void insertEmploee(){
Employee employee = new Employee();
employee.setEmpName("Azad");
employee.setEmpDesignation("Engg");
employee.setEmpSalary(12.5f);
Mockito.doNothing().when(employeeRepository).save(Mockito.any(Employee.class));
employeeRepository.save(employee);
Mockito.verify(employeeRepository, Mockito.times(1)).save(employee);
}
}

Related

Initialize Mocks in test before #BeforeStep

I have a custom reader with an #BeforeStep function in order to initialize some data. These data are comming from an external database.
#Component
public class CustomReader implements ItemReader<SomeDTO> {
private RestApiService restApiService;
private SomeDTO someDTO;
#BeforeStep
private void initialize() {
someDTO = restApiService.getData();
}
#Override
public SomeDTO read() {
...
return someDTO
}
}
In my unit test i need to mock the calls to the external database.
#RunWith(SpringRunner.class)
#SpringBootTest(classes = NedBatchApplication.class)
public class CustomReaderTest {
#Autowired
CustomReader customReader;
#Mock
RestApiService restApiService;
#Before
private void setup() {
MockitoAnnotations.initMocks(this);
ReflectionTestUtils.setField(customReader, "restApiService", restApiService);
Mockito.when(restApiService.getData().thenReturn(expectedData);
}
}
The problem i am facing is the #BeforeStep is executed before the #Before from the unit test, when i lauch my Test. So restApiService.getData() returns null instead of expectedData.
Is there a way to achieve what i want or do i need to do it with a different approach ?
After some reflexion with a co-worker he gave me a solution :
#RunWith(SpringRunner.class)
#SpringBootTest(classes = NedBatchApplication.class)
public class CustomReaderTest {
CustomReader customReader;
#Mock
RestApiService restApiService;
#Before
private void setup() {
MockitoAnnotations.initMocks(this);
Mockito.when(restApiService.getData().thenReturn(expectedData);
this.customReader = new CustomReader(restApiService);
}
#Test
public void test() {
customReader.initialize();
(...)
}
}
Are you certain that the BeforeStep is running before the Before annotation (by using logging or similar?).
It's possible your Mockito invocation is not fully correct. Try using Mockito.doReturn(expectedData).when(restApiService).getData() instead.
As an alternative approach, if the RestApiService was autowired in your custom reader, you'd be able to use the #InjectMocks annotation on the custom reader declaration in your test, which would cause the mocked version of your restApiService to be injected to the class during the test.
Usually when using Spring based tests, try to make dependencies like restApiService (the ones you would like to mock) to be spring beans, and then you can instruct spring to create mock and inject into application context during the application context creation with the help of #MockBean annotation:
import org.springframework.boot.test.mock.mockito.MockBean;
#RunWith(SpringRunner.class)
#SpringBootTest(classes = NedBatchApplication.class)
public class CustomReaderTest {
#MockBean
private RestApiService restApiService;
}

#DataMongoTest fails because of UnsatisfiedDependencyException

I'd like to test my repository method. However when I run my test, it fails because of UnsatisfiedDependencyException. It for some reason tries to create AuthorizationServerConfig (or other bean if I remove #Configuration annotation from this one). It fails cause deeper in dependencies chain it requires RabbitMQ connection pool, that I prefer to not provide in repository test.
The question is why Spring tries to create all those beans not linked to repository logic?
I attempted to exclude all those beans with #DataMongoTest(exludeFilters: ...) and #DataMongoTest(exludeAutoConfiguration: ...) but it had no effect.
The only thing that helped was to add #Profile("!test") to all beans (all! controllers, services, components) in an application, but it smells like a very ugly solution.
Repository class is very simple:
#Repository
public interface ParticipantRepository extends MongoRepository<Participant, String> {
List<Participant> findAllByLoggedInTrueAndAccessTokenExpirationAfter(Date expirationAfter);
}
My test class:
#DataMongoTest()
#RunWith(SpringRunner.class)
public class ParticipantRepositoryTest {
#Autowired
private MongoTemplate mongoTemplate;
#Autowired
private ParticipantRepository repository;
private List<Participant> participants;
#Before
public void setUp() throws Exception {
participants = createParticipants();
repository.saveAll(participants);
}
#After
public void tearDown() throws Exception {
repository.deleteAll();
}
#Test
public void findAllByLoggedInTrueAndExpirationAfter_shouldNotReturnLoggedOutParticipants() {
List<Participant> result = repository.findAllByLoggedInTrueAndAccessTokenExpirationAfter(new Date());
getLoggedOutParticipants().forEach(participant -> assertThat(participant, not(isIn(result))));
}
...
}

Mockito with jUnit ParallelComputer

I am writing integration test for a spring boot controller for concurrent access of APIs. I want to run these tests in parallel using a common setup. I looked at jUnit ParallelComputer but couldn't find a way to create a common setup. Even if I find a way to do the common setup the #Autowired variables are not getting instantiated, they remain null. Am I missing something?
Here is an example of what I am doing:
#RunWith(SpringJUnit4ClassRunner.class)
public class ParallelComputerTest {
#Test
public void test() {
Class[] cls={ParallelTest1.class};
//Parallel all methods in all classes
JUnitCore.runClasses(new ParallelComputer(true, true), cls);
}
}
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(webEnvironment =
SpringBootTest.WebEnvironment.RANDOM_PORT)
#AutoConfigureMockMvc
public class ParallelTest1 {
#Autowired
private MockMvc mockMvc;
#Autowired
private someClass;
#Test public void a(){
//someClass and mockMvc is null here
//do something
}
#Test public void b(){}
}
Why is mockMvc and the other classes I #Autowired null?
I need a way to spin up the server, do some common setup and run the tests in parallel.

Transaction roll back is not working in test case in #Nested class of JUnit5

I use spring-boot, JUnit5, Mybatis.
#SpringJUnitJupiterConfig(classes = {RepositoryTestConfig.class})
#MapperScan
#Rollback
#Transactional
public class TestClass {
#Autowired
private TestMapper testMapper;
#BeforeEach
void init() {
User user = new User();
testMapper.insert(user);
}
#Test
public void test1() {
// (1) success rollback
}
#Nested
class WhenExistData {
#Test
public void test2() {
// (2) rollback not working
}
}
}
(1) is working rollback. And the following log is output.
2017-05-26 22:21:29 [INFO ](TransactionContext.java:136) Rolled back transaction for test context ...
But, (2) is not working. I want to be able to roll back into #Nested.
This is to be expected: the Spring TestContext Framework has never supported "inheritance" for nested test classes.
Thus your "work around" is actually the correct way to achieve your goal at this point in time.
Note, however, that I may add support for "pseudo-inheritance" for nested test classes in conjunction with SPR-15366.
Regards,
Sam (author of the Spring TestContext Framework)
I solved it in the following way..
#SpringJUnitJupiterConfig(classes = {RepositoryTestConfig.class})
#MapperScan
#Rollback
#Transactional
public class TestClass {
#Autowired
private TestMapper testMapper;
#BeforeEach
void init() {
User user = new User();
testMapper.insert(user);
}
#Nested
#SpringJUnitJupiterConfig(classes = {RepositoryTestConfig.class})
#MapperScan
#Rollback
#Transactional
class WhenExistData {
#Test
public void test2() {
}
}
}
I solved it in the following way
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.test.annotation.Rollback;
import org.springframework.transaction.annotation.Transactional;
// JUnit5
#SpringBootTest
public class TestClass {
#Resource
private TestMapper testMapper;
#Test
#Rollback
#Transactional
public void createByTimerId() {
Assertions.assertEquals(1, testMapper.insert());
}
}
Using the annotation NestedTestConfiguration from Spring on the enclosing class did the trick for me. It seems that without it, the nested class won't inherit the config.
#NestedTestConfiguration(NestedTestConfiguration.EnclosingConfiguration.INHERIT)
So maybe on your TestClass you would have your current annotations and then:
#NestedTestConfiguration(NestedTestConfiguration.EnclosingConfiguration.INHERIT)
public class TestClass {
...

Spring data repository not injecting with #Mock in test case class returns null?

Repository object not injecting in testcase class.
Here is my below test class code
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classesExternalProviderMain.class)
#ActiveProfiles(ApplicationConstants.DEVELOPMENT_PROFILE)
#WebAppConfiguration
public class EmployeeServiceTest {
#InjectMocks
EmployeeService employeeService; //not injected null
#Mock
EmployeeRepository employeeRepository;//not injected null
#Test
public void testEmployee() {
Mockito.when(employeeRepository.findByName(Stringname)).thenReturn(getEmployee());
List<Employee> resultedTrackbles = employeeService.getEmployeeByName("mike");
}
private List<Employee> getEmployee(){
//here is the logic to return List<Employees>
}
}
Can you please help me how to inject my "EmployeeRepository" and Do need to write any additional logic.
That's because you are running your test with SpringJUnit4ClassRunner and not with MockitoJUnitRunner.
The mocks need to be initialized with MockitoAnnotations.initMocks:
#Before
public void init() {
MockitoAnnotations.initMocks(this);
}

Categories