I have a #Controller that write a query result into the Model attributes.
When a GETquery arrives, it may be rewritten by a QuerydslBinderCustomizer to translate the query to the database fields accordingly:
#Controller
public class MyController {
#Autowired
private MyEntityRepository dao;
#GetMapping("/test")
public String findAll(Model model,
#QuerydslPredicate(root = MyEntity.class) Predicate predicate) {
model.addAttribute("page", dao.findAll(predicate, Pageable.of(5));
return "/test";
}
}
public interface MyEntityRepository extends
JpaRepository<MyEntity, Long>,
QuerydslPredicateExecutor<MyEntity>,
QuerydslBinderCustomizer<QMyEntity> {
#Override
default void customize(final QuerydslBindings bindings, final QMyEntity entity) {
bindings.bind(entity.somevalue).first((path, value) -> //... create a custom binding of it );
}
}
Question: how could I (unit)-test the QuerydslBinderCustomizer? Because: it is only rendered when a request arrives through the spring MVC layer.
In general, I could test the servlet as follows, but I'm then unable to read the return results from Model object:
#AutoConfigureMockMvc
public class MyTest {
#Test
public void test(#Autowired WebTestClient webTestClient) {
webTestClient.get()
.uri("/test?somevalue=junit")
.exchange()
.expectStatus().isOk();
//TODO how to access the 'Model.page' for assertion?
}
}
Related
I want to test FlashMap assignment of a spring #Controller:
#Controller
public class MyServlet {
#GetMapping("/test")
public String get() {
ServletRequestAttributes reqAttr = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
FlashMap outAttr = RequestContextUtils.getOutputFlashMap(reqAttr.getRequest());
outAttr.put("success", "test");
}
}
}
What how can I actually access the flash attributes from a WebTestClient class?
#SpringBootTest
public class ServletTest {
#Autowired
private WebTestClient;
#Test
public void test() {
client.get().uri("/test")
.expectStatus().isOk()
.expectBody().isEmpty();
//TODO how to validate flash attributes?
}
}
EntityExchangeResult<byte[]> result = client...
.expectBody().returnResult();
MockMvcWebTestClient.resultActionsFor(result)
.andExpect(flash()
.attribute("success", "test");
I am currently trying to use jOOQ in my springboot project to insert certain data given by user from a html form into a MySQL db. This is my MainController responsible for getting data from the form and executing the query through a VisitorRepository: I'm using both add and insertVisitor methods but neither of them are working.
#Controller
public class MainController {
private final VisitorRepository visitorRepository;
#Autowired
public MainController (VisitorRepository visitorRepository) {
this.visitorRepository = visitorRepository;
}
#RequestMapping(value = "/", method = RequestMethod.GET)
public String main() {
return "main";
}
#ResponseBody
#PostMapping("/")
public Phonenum firstSubmit(Phonenum phonenum){
System.out.println(phonenum.getPhonenumber());
visitorRepository.insertVisitor(phonenum.getPhonenumber(),"now", phonenum.getName());
return visitorRepository.add(phonenum);
}
}
VisitorRepository interface:
public interface VisitorRepository {
public Phonenum add(Phonenum visitor);
public List<Phonenum> findAll();
public void insertVisitor(String phoneNumber, String submitTime, String name);
}
And the repository implementation:
#Repository
#Transactional
public class VisitorRepo implements VisitorRepository{
private final DSLContext dslContext;
public VisitorRepo(DSLContext dslContext){
this.dslContext = dslContext;
}
public void insertVisitor(String phoneNumber, String submitTime, String name){
this.dslContext
.insertInto(Phonenum.PHONENUM)
.columns(Phonenum.PHONENUM.PHONENUMBER, Phonenum.PHONENUM.SUBMITTIME, Phonenum.PHONENUM.NAME)
.values(phoneNumber, submitTime, name);
}
public com.demo.visitorlog.model.Phonenum add(com.demo.visitorlog.model.Phonenum visitor) {
this.dslContext
.insertInto(Phonenum.PHONENUM)
.columns(Phonenum.PHONENUM.PHONENUMBER, Phonenum.PHONENUM.SUBMITTIME, Phonenum.PHONENUM.NAME)
.values(visitor.getPhonenumber(), String.valueOf("submit time"), visitor.getName());
System.out.println("ran");
return visitor;
}
I'm not entirely sure how to setup the config class but here is what I have:
#Configuration
public class mainConfig{
#Autowired
private DataSource dataSource;
#Bean
public DataSourceConnectionProvider connectionProvider() {
return new DataSourceConnectionProvider
(new TransactionAwareDataSourceProxy(dataSource));
}
#Bean
public DefaultDSLContext dsl() {
return new DefaultDSLContext(configuration());
}
public DefaultConfiguration configuration() {
DefaultConfiguration jooqConfiguration = new DefaultConfiguration();
jooqConfiguration.set(connectionProvider());
return jooqConfiguration;
}
So I get the System.out.println() after the post request but when I look into my db there isn't anything inserted. Am I missing something? Any sort of help would be greatly appreciated :)
You have to call .execute() to execute the query
this.dslContext
.insertInto(Phonenum.PHONENUM)
.columns(Phonenum.PHONENUM.PHONENUMBER, Phonenum.PHONENUM.SUBMITTIME, Phonenum.PHONENUM.NAME)
.values(visitor.getPhonenumber(), String.valueOf("submit time"), visitor.getName())
.execute();
The problem was with Spring Security automatically enabling csrf Protection which I had to manual disable in the Security Config class using:
#Override
protected void configure(HttpSecurity http) throws Exception{
http.cors().and().csrf().disable();
}
Let's say I have a controller which handles requests such as www.xyz.com/api/<someParam>. This is my controller, and my Service:
#Controller
public class MyController {
#Autowired MyService service;
#RequestMapping(value = "/api/{someParam}", method = RequestMethod.GET)
public String processRequest(
#PathVariable("someParam") String someParam) {
return service.processRequest(someParam);
}
}
#Service
public class MyService {
#Autowired APICaller apiCaller;
public String processRequest(someParam){
SomeObj obj = apiCaller.callApi();
// do something with obj
// return response;
}
}
Based on the param passed in the URL, I need to call some API, do some processing to the API response, and return it. All these APIs have different processing.
Let's say the APICaller interface is like this:
#Service
public interface APICaller {
public SomeObj callAPI();
}
#Service
public class ABC implements APICaller {
#Override
public SomeObj callAPI() {
// calls some REST api, does some processing to response and returns SomeObj
}
}
#Service
public class XYZ implements APICaller {
#Override
public SomeObj callAPI() {
// calls some SOAP api, does some processing to response and returns SomeObj
}
}
So if the param in the url is 'abc', I need to call ABCImpl. And if it is 'xyz', then I need to call XYZImpl. What should I do in the MyService class to instantiate the proper implementation? I might have multiple implementations based on the param, not just these two.
Thanks.
Define a named Map of beans in your configuration class.
#SpringBootApplication
public class Application {
#Bean
ABC abc() {
return new ABC();
}
#Bean
XYZ xyz() {
return new XYZ();
}
#Bean(name="apis")
Map<String, APICaller> apis() {
Map<String, APICaller> map = new HashMap<>();
map.put("xmz", xyz());
map.put("abc", abc());
return map;
}
}
Then inject it as follows:
#Service
public class MyService {
#Resource(name="apis")
Map<String, APICaller> apis;
public String processRequest(String param){
apis.get(param).callApi();
// do required null checks before calling callApi()
// do something with obj
// return response;
}
}
Update
As per you comment if you still wanted the dependencies of APICaller be autowired, this is how to to do it with #Bean
#Bean
ABC abc(DependancyBean1 bean2) {
return new ABC(bean1);
}
#Bean
XYZ xyz(DependancyBean2 bean2) {
return new XYZ(bean2);
}
We are building an application which uses Spring Boot. We write unit tests using TestNG and Mockito. However I find it pretty annoying to write when(...) configuration, I would like to use real components instead. I started to use #Spy components instead of mocks and this works pretty well until I need to put a Spy into a Spy. I'd like to avoid loading a Spring Context if possible, because creation of the context is very slow it looks like overkill for me to load it for at max 5 classes.
Is there any way, how could I use real code instead of Mocks and not loading whole Spring context? Or is my approach wrong at all and I should mock out all other classes then the tested one?
The other way to do this and may take some modifying of code on your end is to do it by constructor injection instead of field injection. Basically taking away any need of the spring context for testing. so the same from the other answer
Class to test
#Service
public class RecordServiceImpl implements RecordService
{
private final RecordRepository recordRepository;
#Autowired
public RecordServiceImpl(RecordRepository recordRepository)
{
this.recordRepository = recordRepository;
}
public Record find(String id)
{
return recordRepository.findOne(id);
}
public List<Record> findAll()
{
return recordRepository.findAll();
}
#Transactional
public Record save(Record record)
{
record.setRecordStatus("F");
return recordRepository.save(record);
}
}
Test Case
//#RunWith(SpringJUnit4ClassRunner.class)
//#ContextConfiguration(classes = {RecordServiceTestConfig.class})
public class RecordServiceTest
{
// #Autowired
private RecordRepository recordRepository = Mockito.mock(RecordRepository.class);
// #Autowired
private RecordService recordService;
#Before
public void setup()
{
Mockito.reset(recordRepository);
recordService = new RecordServiceImpl(recordRepository);
}
#Test
public void testFind()
{
Mockito.when(recordRepository.findOne(Mockito.anyString())).thenReturn(null);
Record record = recordService.find("1");
Assert.assertNull(record);
Mockito.verify(recordRepository, Mockito.times(1)).findOne(Mockito.eq("1"));
}
#Test
public void testSave()
{
Mockito.when(recordRepository.save(Mockito.any(Record.class)))
.thenAnswer(new Answer<Record>()
{
#Override
public Record answer(InvocationOnMock invocation) throws Throwable
{
Record record = (Record) invocation.getArguments()[0];
Assert.assertEquals("F", record.getRecordStatus());
return record;
}
});
Record record = new Record();
record = recordService.save(record);
Assert.assertNotNull(record);
Mockito.verify(recordRepository, Mockito.times(1)).save(Mockito.eq(record));
}
#Test
public void findAll()
{
Mockito.when(recordRepository.findAll()).thenReturn(new ArrayList<Record>());
List<Record> records = recordService.findAll();
Assert.assertNotNull(records);
Assert.assertEquals(0, records.size());
Mockito.verify(recordRepository, Mockito.times(1)).findAll();
}
}
I think your looking for like this with the use of #ContextConfiguration and #Configuration
Class to test
#Service
public class RecordServiceImpl implements RecordService
{
#Autowired
private RecordRepository recordRepository;
public Record find(String id)
{
return recordRepository.findOne(id);
}
public List<Record> findAll()
{
return recordRepository.findAll();
}
#Transactional
public Record save(Record record)
{
record.setRecordStatus("F");
return recordRepository.save(record);
}
}
Test Class
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {RecordServiceTestConfig.class})
public class RecordServiceTest
{
#Autowired
private RecordRepository recordRepository;
#Autowired
private RecordService recordService;
#Before
public void setup()
{
Mockito.reset(recordRepository);
}
#Test
public void testFind()
{
Mockito.when(recordRepository.findOne(Mockito.anyString())).thenReturn(null);
Record record = recordService.find("1");
Assert.assertNull(record);
Mockito.verify(recordRepository, Mockito.times(1)).findOne(Mockito.eq("1"));
}
#Test
public void testSave()
{
Mockito.when(recordRepository.save(Mockito.any(Record.class)))
.thenAnswer(new Answer<Record>()
{
#Override
public Record answer(InvocationOnMock invocation) throws Throwable
{
Record record = (Record) invocation.getArguments()[0];
Assert.assertEquals("F", record.getRecordStatus());
return record;
}
});
Record record = new Record();
record = recordService.save(record);
Assert.assertNotNull(record);
Mockito.verify(recordRepository, Mockito.times(1)).save(Mockito.eq(record));
}
#Test
public void findAll()
{
Mockito.when(recordRepository.findAll()).thenReturn(new ArrayList<Record>());
List<Record> records = recordService.findAll();
Assert.assertNotNull(records);
Assert.assertEquals(0, records.size());
Mockito.verify(recordRepository, Mockito.times(1)).findAll();
}
}
Test Class Configuration
#Configuration
public class RecordServiceTestConfig
{
#Bean
public RecordService recordService()
{
return new RecordServiceImpl();
}
#Bean
public RecordRepository recordRepository()
{
return Mockito.mock(RecordRepository.class);
}
}
the entire test class took 714ms to run the findAll test took 1ms.
If you are looking to configure your testcase using testng with Spring then you to mention
#ContextConfiguration(locations={
"/context.xml","/test-context.xml"})
at class level to load you spring file and extends your class org.springframework.test.context.testng.AbstractTestNGSpringContextTests
Sample
https://dzone.com/articles/spring-testing-support-testng
I am working with Spring MVC application.
I want to create new event:
fill data at page > controller handle this info > saving new event to DB
I have already created DAO layer and repository layer. But at some places, it behaves very strangely. I have created Java configuration for all repositories in the same way.
Here is Repositories Configuration snippet:
#Configuration
#ComponentScan({ "net.lelyak.edu.repository", "net.lelyak.edu.service" })
#Import({ DatabaseDAOConfiguration.class })
public class ApplicationConfiguration {
#Autowired
private UserDAO userDAO;
#Autowired
private EventDAO eventDAO;
#Autowired
private TicketDAO ticketDAO;
#Autowired
private AuditoriumDAO auditoriumDAO;
#Bean
public AuditoriumRepository auditoriumRepository() {
AuditoriumRepository auditoriumRepository = new AuditoriumRepository();
auditoriumRepository.setDao(auditoriumDAO);
return auditoriumRepository;
}
#Bean
public EventRepository eventRepository() {
EventRepository eventRepository = new EventRepository();
eventRepository.setDao(eventDAO);
return eventRepository;
}
I have faced strange behavior at the controller level.
Here is controller code snippet:
#Controller
#RequestMapping("events")
public class EventsController {
#Autowired
private AuditoriumRepository auditoriumRepository;
#Autowired
private EventRepository eventRepository;
#RequestMapping(path = "add", method = RequestMethod.POST)
public String addEvent(#RequestParam Map<String, String> allRequestParams) {
Event newEvent = new Event();
// get auditorium id from request
String auditoryIdString = allRequestParams.get("auditorium");
Long auditoryId = Long.parseLong(auditoryIdString);
Auditorium auditorium = auditoriumRepository.getById(auditoryId);
newEvent.setAuditorium(auditorium);
AuditoriumRepository is auto-wired fine.
Here is snippet from debug view:
but EventRepository isn't:
Configuration is the same for both. One repository is auto-wired fine, second fails. I am newly at Spring. I can't get a clue why does this happen?
Here is snippet of code from EventRepository:
public class EventRepository extends BaseRepository<Event, EventDAO> {
#Autowired
private AuditoriumRepository auditoriumRepository;
#Override
public int put(Event entity) {
auditoriumRepository.put(entity.getAuditorium());
return super.put(entity);
}
AuditoriumRepository code snippet:
public class AuditoriumRepository extends BaseRepository<Auditorium, AuditoriumDAO> {
#Override
public Auditorium preSave(Auditorium entity) {
return entity;
}
For saving new event to DB I have to use exactly EventRepository. It fails, of course, with following stack trace:
java.lang.NullPointerException
at net.lelyak.edu.repository.BaseRepository.put(BaseRepository.java:23)
at net.lelyak.edu.repository.EventRepository.put(EventRepository.java:20)
at net.lelyak.edu.repository.EventRepository$$FastClassBySpringCGLIB$$5de8d2a5.invoke()
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
I am using spring 4.2.4.RELEASE on Windows 10.
UPDATE:
BaseRepository code snippet:
public abstract class BaseRepository<T extends BaseEntity, E extends BaseDAO<T>> {
private E dao;
public E getDao() {
return dao;
}
public void setDao(E dao) {
this.dao = dao;
}
public int put(T entity) {
return dao.save(preSave(entity));
}
I can't understand why with the same configuration and repository structure. One instance is auto-wired by Spring fine, but the second one fails. How to find the root of this problem? And some solution.
UPDATE 2:
I have tried recommended solution, and added next setter to EventRepository:
public void setAuditoriumRepository(AuditoriumRepository auditoriumRepository) {
System.out.println("EventRepository.setAuditoriumRepository");
this.auditoriumRepository = auditoriumRepository;
}
As log message show this setter is executed. But keep failing for the same reason.
How to solve this issue?
i saw your code and the problem is not related to Spring and autowiring process. The problem is in your save method in BaseDAO class:
#Override
public Integer save(ENTITY entity) {
if (entity.getId() == null) {
insert(entity);
} else {
update(entity);
}
return null;
}
if you change the metod to return newly inserted/updated entity id it will work fine.
try to hardcode it just for test :
#Override
public Integer save(ENTITY entity) {
if (entity.getId() == null) {
insert(entity);
} else {
update(entity);
}
return 1;
}
and the problem is raised when you return null from save method then you are doing assignment in the EventsController class which is:
int eventId = eventRepository.put(newEvent); //this is null and throws NullPointerException because you are trying to assign null to primitive variable.
Try to inject the dependencies yourself in the Java #Configuration class. Update your EventRepository so that it has a setter method for the AuditoriumRepository dependency as follows
public class EventRepository extends BaseRepository<Event, EventDAO> {
private AuditoriumRepository auditoriumRepository;
#Override
public int put(Event entity) {
auditoriumRepository.put(entity.getAuditorium());
return super.put(entity);
}
public void setAuditoriumRepository(AuditoriumRepository auditoriumRepository){
this.auditoriumRepository=auditoriumRepository;
}
}
In your ApplicationConfiguration update as follow:
#Bean
public EventRepository eventRepository() {
EventRepository eventRepository = new EventRepository();
eventRepository.setDao(eventDAO);
eventRepository.setAuditoriumRepository(auditoriumRepository());
return eventRepository;
}
The null pointer exception is because auditoriumRepository is not set in the eventRepository bean.
So while creating the EventRepository bean in ApplicationConfiguration.java, we need to set auditoriumRepository as well.
For this I have updated ApplicationConfiguration as below:
public EventRepository eventRepository() {
EventRepository eventRepository = new EventRepository();
eventRepository.setDao(eventDAO);
eventRepository.setAuditoriumRepository(auditoriumRepository());
return eventRepository;
}
and added setter for auditoriumRepository in the EventRepository class
public AuditoriumRepository getAuditoriumRepository() {
return auditoriumRepository;
}
public void setAuditoriumRepository(AuditoriumRepository auditoriumRepository) {
this.auditoriumRepository = auditoriumRepository;
}
This will ensure that the NPE you are seeing will be resolved.
But subsequently we will still get the NPE at a different point now and i.e., at BaseDAO class. The save method is returning a null object and that is causing this NPE.
To resolve this, I have updated the save method of BaseDAO to return a dummy value of 1. You may want to return an appropriate value as per you application needs.
public Integer save(ENTITY entity) {
if (entity.getId() == null) {
insert(entity);
} else {
update(entity);
}
return 1;
}
With these changes, we will able to save the event and proceed to the next screen.