#Service Spring Unit Test too slow - spring

I need to test my Spring Boot app, and I started with the Service testing. But my test seems to take too long, I'm new at this, maybe is not too slow. Can anyone give me some advice, please?
Here is my test:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = ProiectLicentaApplication.class)
#AutoConfigureTestDatabase
#Transactional
public class TestJUnit {
#Autowired
private UserService userService;
#Test
public void testSaveUser(){
User saveToDb = new User("test#gmail.com","test","employee");
User saved = userService.save(saveToDb);
Assert.assertEquals(saveToDb.getEmail(),saved.getEmail());
}
}
This simple test takes 230-245 ms. The save method has Spring PasswordEncoder that encodes the password, but I don't think this should slow it that much.
Service method
public User save(User user) {
String password = passwordEncoder.encode(user.getPassword());
user.setPassword(password);
return userRepository.save(user);
}

Your current test is starting an entire Spring context and this takes time.
For your specific case it may be better to write unit tests. For that you can use JUnit and Mockito. Please check their docs, the examples are straightforward. It may help you to use #Captor (or ArgumentCaptor)
Usually integration tests take more time because of the interaction between the components and the systems.

Related

Mocking Repositories to test Service in Spring

I occurred some failures after trying to mock repositories to unit test my services in Spring-Boot
Thats what I have (simplified)
#ExtendWith(SpringExtension.class)
#ExtendWith(MockitoExtension.class)
#SpringBootTest
#ActiveProfiles("test")
public class UserTest{
#InjectMocks
private UserServiceImpl userService;
#Mock
private UserRepostiory userRepository;
#Before
public void setUp() {
User user = new User(1L, "email#email", "name");
when(userRepostitory.findById(1L)).thenReturn(Optional.of(user));
}
#Test
public void findUserByIdReturnsUser() {
User user = userService.getById(1L); => always throws error in Service, that no User is found with that Id, it calls the regular Repository: mock does nothing
assertEquals(1L,user.getId());
}
}
But I never get the User returned when the service calls the repo. I am kinda new to Unit Testing, and I am pretty sure, that I miss something here.
In the setUp you do:
when(userRepostitory.findById(1L)).thenReturn(Optional.of(user));
But in the Test you call
User user = userService.getById(1L);
Either mock getById or call findById
"Repostiory" | "Repostitory" looks like a typo error.
Annotate the test class with #RunWith(SpringRunner.class)

What kind of test shall I use in my spring project(and am I doing it right)?

My project is a simple management system for shop which is connected to MySQL database.
I only have JUnit test like this one(is this test written correctly?):
#RunWith(SpringRunner.class)
#DataJpaTest
#AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class EmployeeRepositoryIntegrationTest
{
#Autowired
private TestEntityManager entityManager;
#Autowired
private EmployeeRepository employeeRepository;
#Test
public void whenFindByLastName_thenReturnEmployee()
{
User employee = new User("UserName","password","John",
"Smith","Adress Test","123123123","CityTest");
entityManager.persist(employee);
entityManager.flush();
User result = userRepository.findUserByLastName(employee.getLastName()).get(0);
assertThat(result.getLastName()).isEqualTo(employee.getLastName());
}
}
Should I add Mockito Tests, and what kind of test should I add in future?
I would avoid Mockito to test you JPA repoistories.
Better to seed an in-memory database (which can be spun up and torn down) with real test data.
If you're using the #DataJpaTest annotation you're expected to use sql to seed your database, look at this #DataJpaTest example. You can use sql files and get rid of the TestEntityManager.
Take a look at this DBUnit example. You add your test data in an XML file in your resources directory.

Is it worthy using AOP in a Spring-boot application?

A few days ago, I posted this question asking whether there is a newer approach to Spring AOP and mockito.
While I understand how to use AOP, I am still missing on its returned value. The whole endeavour has shown me that it's not really popular - at least there aren't that many recent posts.
If I comment out the annotations #Aspect and #Configuration in my LoggingAspect class, effectively rendering it non-aop, all my tests are green. If I switch it back on, I start getting a load of NullPointerExceptions and loads of other errors on my mocked test classes.
I wonder if it is worth the hassle.
EDIT adding more detail from my specific implementation.
Controller:
#RestController
public class EndpointController {
private EndpointService endpointService;
#Autowired
public EndpointController(EndpointService endpointService) {
this.endpointService = endpointService;
}
#PostMapping(path = "/endpoint", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
private #ResponseBody EndpointResponse doSomething(//... //, #RequestBody SomeObject someObject) throws Exception {
return endpointService.doSomething(someObject);
}
}
In my test class, I have:
#RunWith(SpringRunner.class)
public class EndpointControllerTest {
#Autowired
private MockMvc mockMvc;
#Test
public void shouldBeSuccessfulAccessingTheEndpoint() throws Exception {
SomeObject someObject = new SomeObject(// values //);
ObjectMapper mapper = new ObjectMapper();
String payload = mapper.writeValueAsString(someObject);
mockMvc.perform(post("/endpoint").contentType(MediaType.APPLICTION_JSON).content(payload)).andExpect(status().isOK));
}
}
It fails and throws a NullPointerException. When debugging, the endpointService is always null.
AOP is great for cross-cutting concerns:
Logging (we use it for access and performance logging)
Validation (such as used by Bean Validation, JSR-380)
Transactional scopes (built into frameworks such as JEE and Spring)
Security checks (e.g. Shiro)
and many more.
It could be used for other purposes, such as extending/wrapping existing functionality, though that is definitely not something I'd recommend, and fortunately never became popular, as it seems.
AOP is as valid as ever. It's used for transactions, logging, metrics, etc.
I think there was period where it might have been overused as decorators.
Production and testing are different matters.
If you're unit testing a class, it suggests that you aren't testing the aspects. You could make those aspects conditional based on profile.
If the proper operation of your object depends on the aspect, because it modifies the input, perhaps you should rethink.

Spring MockMvc not taking roles into account

I have API endpoints which require a user to hold a specific role. Therefore, in some of my tests I attempt to reach these endpoints and expect a 401 error, however I get 200. I am using MockMvc to perform the calls.
The following are some snippets of the controller class with one of the methods that I am testing:
#RestController
public class MyController {
#GetMapping("/getcurrentuser")
public User getCurrent() {
...code
}
}
The following is my test class (only showing the respective test method and variables):
#RunWith(SpringRunner.class)
#WebMvcTest(MyController.class)
#ContextConfiguration(classes = MyController.class)
public class MyControllerTest {
#Autowired
private MockMvc mockMvc;
#Test
public void testGetCurrentFailedDueToIncorrectRole() throws Exception {
mockMvc.perform(get("/api/getcurrentuser")
.with(user(USER_NAME).password(PASSWORD)))
.andExpect(status().isUnauthorized());
}
}
I have also have a spring security config class, however I'm not sure if it's being brought into context in this test (sorry I'm still fairly new to spring and unit testing). Inside this class I have the following line of code:
.antMatchers("/api/**").hasAnyRole("ADMIN", "READ_ONLY")
The test showed previously fails, as I said I get 200. Now at this point I think that I'm doing something wrong in the configuration of this test and that is why roles are not being accounted for. Or maybe I am confused on how the ".with" part works.
Any form of help would be appreciated.
If you are using Spring Boot, you might want to try using #SpringBootTest and #AutoConfigureMockMvc.
https://spring.io/guides/gs/testing-web/
Exact opposite problem (may be useful to go off of)

spring aspect being applied outside of app context (in stubbed out unit test)

Here's a weird one. I've got a few tests failing because an aspect is being applied, so an autowired service is null, bad things ensue. The issue is that I can't understand how the aspect is even being applied, since in the test I construct the object under test with new.
#RunWith(MockitoJUnitRunner.class)
public class TheControllerTest {
#Spy
private TheController controller = new TheController();
#Mock
private HttpServletRequest request;
#Mock
private ConfigService configService;
....
#Before
public void setup() {
controller.setConfigService(configService);
....
}
#Test
public void testGetAccountsList() throws Exception {
Mockito.when(accountService.getAllAccounts()).thenReturn(Arrays.asList(account1, account2));
Map<String, Object> result = controller.getAccountsList(request);
...
}
}
I'm obviously omitting plenty of code, but really, I just don't understand how, given how controller is instantiated, it could have had the advice applied.
One possible reason could be if you are running this in Eclipse - in a project with ajbuilder enabled, even if you are explicitly expecting Spring AOP through dynamic proxies, ajbuilder would actually perform compile team weaving, and hence you would see advice enhanced classes even using normal "new". Can you please check this, the fix would be to disable "ajbuilder" - here is one reference - JUnit weaving wrong Spring AOP Bean

Resources