I have an annotation that pulls in some configurations (via #Import). I want to test running with and without that annotation. I want to do this in one test class.
I know that I can change the spring context per method #DirtiesContext(classMode = BEFORE_EACH_TEST_METHOD), but I don't know how to have it run with or without the annotation on different methods.
How would I achieve this?
What I want to do:
package com.test.reference.cors;
import com.test.EnableCors;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.WebApplicationContext;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.options;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
#RunWith(SpringJUnit4ClassRunner.class)
#WebMvcTest(secure = false)
#ContextConfiguration(classes = {ControllerConfig.class, ReferenceController.class})
public class TestCORS
{
private MockMvc mockMvc;
private ObjectMapper objectMapper;
#Autowired
private RestTemplate restTemplate;
#Autowired
private WebApplicationContext webApplicationContext;
#Before
public void setup()
{
//Create an environment for it
mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext)
.dispatchOptions(true).build();
//Create our marshaller
objectMapper = new ObjectMapper();
}
#Test
public void testWithoutCors() throws Exception
{
//Call to test a date
MvcResult result = mockMvc.perform(
options("/v1/testdate")
.contentType(MediaType.APPLICATION_JSON)
//CORS HEADERS
.header("Access-Control-Request-Method", "DELETE")
.header("Origin", "https://evil.com")
).andExpect(status().isForbidden())
.andReturn();
}
#Test
#EnableCors
public void testWithCors() throws Exception
{
//Call to test a date
MvcResult result = mockMvc.perform(
options("/v1/testdate")
.contentType(MediaType.APPLICATION_JSON)
//CORS HEADERS
.header("Access-Control-Request-Method", "POST")
.header("Origin", "http://evil.com")
).andExpect(status().isOk())
.andReturn();
}
}
Using nested classes, you could do something like this:
class NewFeatureTest {
#SpringBootTest
protected static class NewFeatureWithDefaultConfigTest {
#Autowired
ApplicationContext context;
#Test
void yourTestMethod() {
}
#Configuration(proxyBeanMethods = false)
#EnableAutoConfiguration
protected static class Config {
// your 1st config
}
}
#SpringBootTest
protected static class NewFeatureWithDefaultsTests {
#Autowired
ApplicationContext context;
#Test
void yourOtherTestMethod() {
}
#Configuration(proxyBeanMethods = false)
#EnableAutoConfiguration
protected static class NoDefaultsConfig {
// your 2nd config
}
}}
Related
EDIT: One problem was that Tracing.current() was null. I fixed this with the new #BeforeEach instead of the old #BeforeTestMethod:
Tracer tracer;
#BeforeEach
void init() {
tracer = Tracing.newBuilder().build().tracer();
TraceContext ctx = TraceContext.newBuilder().traceId(17).spanId(17).build();
Span span = tracer.toSpan(ctx);
tracer.withSpanInScope(span);
}
Yet, updateValue still doesn't work as there are no extras in the context, so nothing to update...
Following the ideas like in those answers, I'm trying to use BaggageFields in one of my tests. All the objects are not null, but updateValue returns false and the test fails with BaggageTest.baggageTest:40 expected: <hello> but was: <null>. As said, I have no idea why the updateValue method is not working.
import static org.junit.jupiter.api.Assertions.assertEquals;
import brave.baggage.BaggageField;
import brave.baggage.CorrelationScopeConfig;
import brave.context.slf4j.MDCScopeDecorator;
import brave.propagation.CurrentTraceContext;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.sleuth.ScopedSpan;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.event.annotation.BeforeTestMethod;
import org.springframework.test.context.junit.jupiter.SpringExtension;
#Slf4j
#ExtendWith(SpringExtension.class)
#ContextConfiguration
public class BaggageTest {
#Autowired
ApplicationContext context;
#BeforeTestMethod
void init() {
Tracer tracer = context.getBean(Tracer.class);
ScopedSpan span = tracer.startScopedSpan("test");
}
#Test
void baggageTest() {
BaggageField fooBar = context.getBean("fooBar", BaggageField.class);
log.info("updateValue {}", fooBar.updateValue("hello"));
assertEquals("hello", fooBar.getValue());
}
#Configuration
static class Config {
private BaggageField findOrCreate(String name) {
BaggageField field = BaggageField.getByName(name);
if (field == null) {
field = BaggageField.create(name);
}
return field;
}
#Bean("fooBar")
BaggageField fooBar() {
return findOrCreate("fooBar");
}
#Bean
CurrentTraceContext.ScopeDecorator mdcScopeDecorator() {
return MDCScopeDecorator.newBuilder()
.clear()
.add(CorrelationScopeConfig.SingleCorrelationField.newBuilder(fooBar())
.flushOnUpdate()
.build())
.build();
}
}
}
My solution is to manually build the TraceContext, using the following snippet, being careful that BaggageFields is brave.internal.baggage.BaggageFields.
#Autowired
BaggageField field;
Tracer tracer;
#BeforeEach
void init() {
tracer = Tracing.newBuilder().build().tracer();
ArrayList<BaggageField> list = new ArrayList<>();
list.add(field);
TraceContext ctx = TraceContext.newBuilder()
.addExtra(BaggageFields.newFactory(list,2).create())
.traceId(17).spanId(17).build();
Span span = tracer.toSpan(ctx);
tracer.withSpanInScope(span);
}
I wrote a JUnit 5 test for my service in my Spring Boot application.
I used #MockBean to mock PasswordEncoder and other beans but I obtain a NullPointerException.
I always obtain a NullPointerException during the when call :
when(compteRepository.getByLogin(anyString())).thenReturn(Optional.of(acc));
Service
package com.compte.application.impl;
import com.compte.application.CompteService;
import com.compte.domain.exceptions.EntityNotFoundExcpetion;
import com.compte.domain.model.Compte;
import com.compte.domain.model.CompteUpdatedData;
import com.compte.domain.repository.CompteRepository;
import com.compte.domain.utils.CompteUtil;
import lombok.AllArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.crypto.password.PasswordEncoder;
import java.time.LocalDate;
import java.util.Optional;
/**
* #author mbint
*/
#AllArgsConstructor
public class CompteServiceImpl implements CompteService{
private final static Logger LOGGER = LoggerFactory.getLogger(CompteService.class);
private CompteRepository CompteRepository;
private PasswordEncoder passwordEncoder;
#Override
public Optional<Compte> getByLogin(String login) {
return CompteRepository.getByLogin(login);
}
#Override
public void update(final Long id, CompteUpdatedData updatedData) {
Optional<Compte> optional = CompteRepository.getById(id);
if(optional.isPresent()) {
Compte Compte = optional.get();
Compte.setFirstName(updatedData.getFirstName());
Compte.setLastName(updatedData.getLastName());
CompteRepository.save(Compte);
} else {
throw new EntityNotFoundExcpetion("Compte: " + id + " not found !!");
}
}
}
Junit Test
package com.compte.application;
import com.compte.application.impl.CompteServiceImpl;
import com.compte.domain.model.Compte;
import com.compte.domain.model.CompteUpdatedData;
import com.compte.domain.repository.compteRepository;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.security.crypto.password.PasswordEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import static org.mockito.Mockito.*;
/**
* #author mbint
*/
public class CompteServiceImplTest {
private final static String PASSWORD = "Passw00rd";
#MockBean
private compteRepository compteRepository;
#MockBean
private PasswordEncoder passwordEncoder;
private CompteService CompteService = new CompteServiceImpl(compteRepository, passwordEncoder);
#DisplayName(("Should return existing user"))
#Test
private void given_login_then_return_existing_user() {
Compte acc = Compte.builder().id(1L)
.firstName("Luc")
.lastName("JOJO")
.login("xxx#gmail.com")
.password("xxxxxxxxxxxxxxx")
.build();
when(compteRepository.getByLogin(anyString())).thenReturn(Optional.of(acc));
Optional<Compte> optional = CompteService.getByLogin("xxx#gmail.com");
Compte Compte = optional.get();
Assertions.assertSame(1L, acc.getId());
Assertions.assertSame("xxx#gmail.com", Compte.getLogin());
}
#DisplayName("Should update existing user")
#Test
public void given_edited_Compte_then_update_user() {
Compte acc = Compte.builder().id(1L)
.firstName("Luc")
.lastName("JOJO")
.email("xxx#gmail.com")
.password("xxxxxxxxxxxxxxx")
.build();
when(compteRepository.getById(anyLong())).thenReturn(Optional.of(acc));
CompteUpdatedData updatedData = CompteUpdatedData.builder()
.firstName("Moos")
.lastName("Man")
.build();
CompteService.update(1L, updatedData);
Assertions.assertSame("Moos", acc.getFirstName());
}
private List<Compte> getComptes() {
List<Compte> Comptes = new ArrayList<>();
Compte acc1 = Compte.builder()
.id(1L)
.firstName("Luc")
.lastName("JOJO")
.email("xxx#gmail.com")
.login("xxx#gmail.com")
.build();
Comptes.add(acc1);
Compte acc2= Compte.builder()
.id(2L)
.firstName("Jean")
.lastName("KELLY")
.email("jean.kelly#gmail.com")
.login("jean.kelly#gmail.com")
.build();
Comptes.add(acc2);
Compte acc3= Compte.builder()
.id(3L)
.firstName("Marc")
.lastName("BARBY")
.email("marc.barby#gmail.com")
.login("marc.barby#gmail.com")
.build();
Comptes.add(acc3);
return Comptes;
}
}
Spring boot application
package com.compte;
import com.compte.application.CompteService;
import com.compte.application.impl.CompteServiceImpl;
import com.compte.domain.repository.CompteRepository;
import com.compte.infrastructure.repository.database.CompteDBRepositiry;
import com.ombsc.bargo.common.config.SwaggerConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import org.springframework.hateoas.client.LinkDiscoverer;
import org.springframework.hateoas.client.LinkDiscoverers;
import org.springframework.hateoas.mediatype.collectionjson.CollectionJsonLinkDiscoverer;
import org.springframework.plugin.core.SimplePluginRegistry;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import java.util.ArrayList;
import java.util.List;
#ComponentScan({"com.compte.interfaces.interfaces"})
#SpringBootApplication
#Import({SwaggerConfig.class})
public class CompteApplication {
public static void main(String[] args) {
SpringApplication.run(CompteApplication.class, args);
}
#Bean
public CompteRepository getRepository() {
return new CompteDBRepositiry();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
public CompteService CompteService(CompteRepository repository, PasswordEncoder passwordEncoder) {
return new CompteServiceImpl(repository, passwordEncoder);
}
#Bean
public LinkDiscoverers discovers() {
List<LinkDiscoverer> plugins = new ArrayList<>();
plugins.add(new CollectionJsonLinkDiscoverer());
return new LinkDiscoverers(SimplePluginRegistry.create(plugins));
}
}
The mocks need to be initialized before they can be used. There are several options to do this.
The first option would be to use #SpringExtension which will initialize the mocks annotated with #MockBean:
#ExtendWith(SpringExtension.class)
public class CompteServiceImplTest {
#Autowired
private CompteService CompteService;
#MockBean
private compteRepository compteRepository;
// ...
}
This will make sure that the repository bean is mocked before the service bean is autowired.
However, since you are writing a unit test for the service, you don't need the Spring extension at all. The second option is to use #Mock instead of #MockBean, and call #InjectMocks in conjunction with the MockitoExtension for constructing the service under test:
#ExtendWith(MockitoExtension.class)
public class CompteServiceImplTest {
#InjectMocks
private CompteService CompteService;
#Mock
private compteRepository compteRepository;
// ...
}
Alternatively, you could just call MockitoAnnotations.initMocks(), which will initialize the mocks annotated with #Mock, and use constructor injection for your service:
public class CompteServiceImplTest {
private CompteService CompteService;
#Mock
private compteRepository compteRepository;
#BeforeEach
void setUp() {
MockitoAnnotations.initMocks(this);
CompteService = new CompteServiceImpl(compteRepository, ...);
}
// ...
}
Finally, you could do it all without annotations just by calling Mockito.mock() directly:
public class CompteServiceImplTest {
private compteRepository compteRepository;
#BeforeEach
void setUp() {
compteRepository = Mockito.mock();
CompteService = new CompteServiceImpl(compteRepository, ...);
}
// ...
}
URL : http://X.X.X.X/APPLICATION/abc?a=1
Is my URL correct?
JAVA Code:
#RequestMapping(value = "/abc?", method = RequestMethod.GET)
#ResponseBody
public ModelAndView page (#RequestParam(value = "a") String a) {
...
Code Logic
...
}
Am I handling it correctly?
Remove the question mark after abc.
value = "/abc"
this is how I am handling the url params. I have also attached the test code below to make it easier to understand.
Here's my controller
package com.example.demo;
import org.springframework.web.bind.annotation.*;
#RestController
#RequestMapping("/APPLICATION")
public class DemoController {
#GetMapping("/abc")
public #ResponseBody String getAbc(#RequestParam String a) {
return a;
}
}
And here's the test code
package com.example.demo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;
import static org.hamcrest.Matchers.equalTo;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
#SpringBootTest
#AutoConfigureMockMvc
class DemoApplicationTests {
#Autowired
private MockMvc mockMvc;
#Test
void contextLoads() {
}
#Test
public void shouldGetParamFromUrl() throws Exception {
this.mockMvc.perform(get("/APPLICATION/abc?a=1"))
.andDo(print()).andExpect(status().isOk())
.andExpect(content().string(equalTo("1")));
this.mockMvc.perform(get("/APPLICATION/abc?a=99"))
.andDo(print()).andExpect(status().isOk())
.andExpect(content().string(equalTo("99")));
}
}
I have below classes.
#Service
class RestService {
#Autowired
private RestTemplate restTemplate;
public ResponseEntity<String> callService(String param) {
return restTemplate.exchange(....);
}
}
#Service
class CallingService{
#Autowired
private RestService restService;
public ResponseDTO getResponse(String param) {
ResponseEntity<String> response = restService.callService(param);
ResponseDTO responseDTO = convert(response)// JSON Convertor here
return responseDTO;
}
}
Now I want to write test class for CallingService class.
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.IOException;
import javax.xml.datatype.DatatypeConfigurationException;
import org.apache.cxf.helpers.IOUtils;
import org.junit.Before;
import org.junit.Rule;
import org.junit.jupiter.api.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
#RunWith(MockitoJUnitRunner.class)
#SpringBootTest
class CallingServiceTest{
#InjectMocks
private CallingService service;
#Mock
private RestService restService;
#Test
public testGetResponse(){
ResponseDTO dto = createDummyObject();
HttpHeaders header = new HttpHeaders();
header.setContentType(MediaType.APPLICATION_JSON);
ResponseEntity<String> responseEntity = new ResponseEntity<>("response message", header,
HttpStatus.OK);
when(restService.callService(Mockito.anyString())).thenReturn(responseEntity);
// mocking converter here
dto = service.getResponse("param");
//assert conditions here onwards
}
}
The invocation at line service.getResponse("param") gives NullPointerException. On debugging I found that response received in CallingService.getResponse() is null (i.e. restService.callService(param) returned null) and hence code broken into convert() method.
I tried with a lot of code manipulations but no luck. Hope anyone might have answer for this.
I finally found a workaround by combining flavours of above two answers.
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import org.apache.cxf.helpers.IOUtils;
import org.junit.Before;
import org.junit.Rule;
import org.junit.
import org.junit.Test;
import org.junit.jupiter.api.BeforeEach;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
#RunWith(MockitoJUnitRunner.class)
#SpringBootTest
public class CallingServiceTest{
#InjectMocks
private CallingService service;
#Mock
private RestService restService;
#BeforeEach
public void setup(){
MockitoAnnotations.init(this);
}
#Test
public testGetResponse(){
ResponseDTO dto = createDummyObject();
HttpHeaders header = new HttpHeaders();
header.setContentType(MediaType.APPLICATION_JSON);
ResponseEntity<String> responseEntity = new ResponseEntity<> ("response message", header, HttpStatus.OK);
when(restService.callService(Mockito.anyString())).thenReturn(responseEntity);
// mocking converter here
dto = service.getResponse("param");
//assert conditions here onwards
}
}
You can't use both #RunWith(MockitoJUnitRunner.class) and #SpringBootTest. They're both setting up JUnit Rules and you can only have one rule active.
You need to use Spring annotations. Instead of #Mock use #MockBean so Spring can properly inject it to the service.
#SpringBootTest
class CallingServiceTest{
#Autowired
private CallingService service;
#MockBean
private RestService restService;
#Test
public testGetResponse(){
ResponseDTO dto = createDummyObject();
HttpHeaders header = new HttpHeaders();
header.setContentType(MediaType.APPLICATION_JSON);
ResponseEntity<String> responseEntity = new ResponseEntity<>("response message", header,
HttpStatus.OK);
when(restService.callService(Mockito.anyString())).thenReturn(responseEntity);
// mocking converter here
dto = service.getResponse("param");
//assert conditions here onwards
}
}
Alternatively, you can use just Mockito since you don't really need to initialize SpringContext for this test I think.
#RunWith(MockitoJUnitRunner.class)
class CallingServiceTest{
#InjectMocks
private CallingService service;
#Mock
private RestService restService;
#Test
public testGetResponse(){
ResponseDTO dto = createDummyObject();
HttpHeaders header = new HttpHeaders();
header.setContentType(MediaType.APPLICATION_JSON);
ResponseEntity<String> responseEntity = new ResponseEntity<>("response message", header,
HttpStatus.OK);
when(restService.callService(Mockito.anyString())).thenReturn(responseEntity);
// mocking converter here
dto = service.getResponse("param");
//assert conditions here onwards
}
}
Based on your import you are using a combination of Junit4 and Junit5.
This will not work properly.
Steps to run with Junit5
Change your imports to org.junit.jupiter.api.*
Change #Before to #BeforeEach.
Remove #SpringBootTest not required with Junit5
Change #RunWith(MockitoJUnitRunner.class) to #ExtendWith(MockitoExtension.class)
Please find the changed code below
#ExtendWith(MockitoExtension.class)
class CallingServiceTest{
#InjectMocks
private CallingService service;
#Mock
private RestService restService;
#Test
public testGetResponse(){
ResponseDTO dto = createDummyObject();
HttpHeaders header = new HttpHeaders();
header.setContentType(MediaType.APPLICATION_JSON);
ResponseEntity<String> responseEntity = new ResponseEntity<>("response message", header,
HttpStatus.OK);
when(restService.callService(Mockito.anyString())).thenReturn(responseEntity);
// mocking converter here
dto = service.getResponse("param");
//assert conditions here onwards
}
}
If you want to run with Junit4 change your import for #Test to import org.junit.Test from import org.junit.jupiter.api.Test
Either one of the solutions will work.
I am trying to run tests on a controller class and it has atleast a method which internally uses a DAO to retrieve information from the DB (MySQL).
The problem I have is that the dao method is giving null and I end up with NullPointerException error.
How do I tests a class which has methods that internally use a database connection?
Haven't been able to find any useful post/answer.
Project structure:
src
main
java
[package]
RegisterController.java
Config.java // configuration class
test
java
[package]
RegisterControllerTest.java
RegisterController.java
package com.webapp.controller;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import com.webapp.Config;
import com.webapp.dao.AccountDao;
#Controller
public class RegisterController {
#Autowired
AccountDao accDao;
public String validateUsername(String uname){
List<String> errors = new ArrayList<String>();
// ... unrelated code
// NullPointerException thrown here
if(accDao.getAccountByUsername(uname) != null)
errors.add("err#taken");
return errors.toString();
}
}
RegisterControllerTest.java
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.springframework.boot.test.context.SpringBootTest;
import com.webapp.controller.RegisterController;
import com.webapp.Config;
#SpringBootTest
public class RegisterControllerTest {
#Mock
private Config config;
private RegisterController rc;
#BeforeEach
public void init() {
config = Mockito.mock(Config.class);
rc = new RegisterController();
}
#Test
public void testValidateUsername() {
assertEquals("[]", rc.validateUsername("Username123")); // N.P.E
}
}
Config.java
package com.webapp;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import com.webapp.dao.AccountDao;
import com.webapp.dao.AccountDaoImpl;
import com.webapp.dao.Dao;
#Configuration
#ComponentScan(basePackages = { "com.webapp.controller", "com.webapp.dao", "com.webapp.test" })
public class Config {
private static class Database {
private static String host = "127.0.0.1";
private static String user = "root";
private static String pass = "root";
private static String dbname = "memedb";
private static int port = 3306;
public static String getUrl() {
return "jdbc:mysql://"+host+":"+port+"/"+dbname+"?serverTimezone=Europe/Stockholm";
}
}
#Bean
public DriverManagerDataSource getDataSource() {
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
ds.setUrl(Database.getUrl());
ds.setUsername(Database.user);
ds.setPassword(Database.pass);
return ds;
}
#Bean
public AccountDao getAccDao() {
return new AccountDaoImpl(getDataSource());
}
}
Instead of mocking config, mock the Dao. You are getting NPE, because the mocked config is not setting #Autowired accDao... so your accDao == null:
#Controller
public class RegisterController {
AccountDao accDao;
public RegisterController(AccountDao accDao) {
this.accDao = accDao;
}
...
}
#BeforeEach
public void init() {
accDaoMock = Mockito.mock(AccountDao.class);
rc = new RegisterController(accDaoMock);
}
#Test
public void testValidateUsername() {
when(accDaoMock.getAccountByUsername("Username123")).thenReturn(null);
assertEquals("[]", rc.validateUsername("Username123"));
}
Why are you configuring the connection DB programmatically? I advise you configure the connection DB with autoconfiguration of Spring Boot.
The DAO object have to mock in an unit test.
Here is a good article about the Junit test for a Spring Boot App.