data.xml
file. You need to change 3 to 4 in the package name org.springframework.orm.hibernate4
, remove the configLocation
and configurationClass
parameters in the configLocation
and instead add the packagesToScan
parameter where to transfer the list of class packages with Hibernate mapping from hibernate.cfg.xml
. This file itself can be deleted, we no longer need it. As a result, the sessionfactory
bin takes the form: <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="packagesToScan"> <list> <value>net.schastny.contactmanager.domain</value> <value>com.acme.contactmanager.domain</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.hbm2ddl.auto">create-drop</prop> <prop key="hibernate.dialect">${jdbc.dialect}</prop> <prop key="hibernate.connection.charSet">UTF-8</prop> </props> </property> </bean>
src/test/resources
directory, copy security.xml security.xml
settings into it, and create testdb.properties
property file for the database. You can do without it, but again, for educational purposes, we will see how you can set properties in bins from the outside. File contents db.user.name=sa db.user.pass=
log4j.xml
and with resources on it all. Go to the source code.src/test/groovy
, package com.acme.contactmanager.test
In order for the maven to find our grooves when building from the command line, we’ll add build-helper-maven-plugin to pom.xml
TestConfig.groovy
@Configuration @ComponentScan(['net.schastny.contactmanager.dao', 'com.acme.contactmanager.dao', 'net.schastny.contactmanager.web', 'net.schastny.contactmanager.service']) @PropertySource('classpath:testdb.properties') @ImportResource('classpath:security.xml') @EnableTransactionManagement class TestConfig { // ... }
testdb.properties
security.xml
By the way, about the transaction. We have interfaces and implementations for the DAO and service classes, but in general we can confine ourselves to the implementation class alone. In this case, the annotation will need to specify that the proxyTarget is created automatically, otherwise there will be problems: @EnableTransactionManagement(proxyTargetClass = true)
testdb.properties
to class attributes using @Value
class TestConfig { @Value('${db.user.name}') String userName @Value('${db.user.pass}') String userPass // ... }
LocalSessionFactoryBean
, where we will use the properties obtained. Here we see the packagesToScan
already familiar to us. @Bean public LocalSessionFactoryBean sessionFactory() { LocalSessionFactoryBean bean = new LocalSessionFactoryBean() bean.packagesToScan = [ 'com.acme.contactmanager.domain', 'net.schastny.contactmanager.domain'] as String[] Properties props = new Properties() props."hibernate.connection.driver_class" = "org.h2.Driver" props."hibernate.connection.url" = "jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;MVCC=TRUE;DB_CLOSE_ON_EXIT=FALSE" props."hibernate.connection.username" = userName props."hibernate.connection.password" = userPass props."hibernate.dialect" = "org.hibernate.dialect.H2Dialect" props."hibernate.hbm2ddl.auto" = "create-drop" props."hibernate.temp.use_jdbc_metadata_defaults" = "false" bean.hibernateProperties = props bean }
This hibernate.temp.use_jdbc_metadata_defaults = false
thing helps when it slows down the context to retrieve metadata from the database
HibernateTransactionManager
@Bean public HibernateTransactionManager transactionManager() { HibernateTransactionManager txManager = new HibernateTransactionManager() txManager.autodetectDataSource = false txManager.sessionFactory = sessionFactory().object txManager }
MockMvcTest.groovy
@RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration @ContextConfiguration(classes = [ TestConfig.class ] ) class MockMvcTest { @Autowired WebApplicationContext wac MockMvc mockMvc @Before public void setup() { this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).dispatchOptions(true).build() } }
home()
method is a good candidate for the test case, where there is a simple redirect @RequestMapping("/") public String home() { return "redirect:/index"; }
@Test public void home() { MockHttpServletRequestBuilder request = MockMvcRequestBuilders.get("/") ResultActions result = mockMvc.perform(request) result.andExpect(MockMvcResultMatchers.redirectedUrl("/index")) }
TheandExpect()
function provides great opportunities for checking the result obtained, here are examples from Javadoc, which give a general idea of its work:
mockMvc.perform(get("/person/1")) .andExpect(status.isOk()) .andExpect(content().mimeType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$.person.name").equalTo("Jason")); mockMvc.perform(post("/form")) .andExpect(status.isOk()) .andExpect(redirectedUrl("/person/1")) .andExpect(model().size(1)) .andExpect(model().attributeExists("person")) .andExpect(flash().attributeCount(1)) .andExpect(flash().attribute("message", "success!"));
@RequestMapping("/index") public String listContacts(Map<String, Object> map) { map.put("contact", new Contact()); map.put("contactList", contactService.listContact()); map.put("contactTypeList", contactService.listContactType()); return "contact"; }
@Test public void index() { ResultActions result = mockMvc.perform(MockMvcRequestBuilders.get("/index")) result.andExpect(MockMvcResultMatchers.view().name("contact")) .andExpect(MockMvcResultMatchers.model().attributeExists("contact")) .andExpect(MockMvcResultMatchers.model().attributeExists("contactList")) .andExpect(MockMvcResultMatchers.model().attributeExists("contactTypeList")) }
MvcResult mvcResult = result.andReturn() assert mvcResult.modelAndView.model.contactTypeList.size() == 3
@RequestMapping(value = "/add", method = RequestMethod.POST) public String addContact(@ModelAttribute("contact") Contact contact, BindingResult result) { contactService.addContact(contact); return "redirect:/index"; }
@ModelAttribute Contact contact
parameter. But it is not all that bad. A quick googling request for “mockmvc Model Attribute” here gives the result . Such mapping can simply be replaced by a set of query parameters. The function of adding parameters to the query is quite expected to look like this: param(Stirng name, String... values)
. We write @Autowired ContactService contactService @Test public void add() { // , def contacts = contactService.listContact() assert !contacts // def contactTypes = contactService.listContactType() assert contactTypes // POST-, mockMvc.perform(MockMvcRequestBuilders.post("/add") .param("firstname",'firstname') .param("lastname",'lastname') .param("email",'firstname.lastname@gmail.com') .param("telephone",'555-1234') .param("contacttype.id", contactTypes[0].id.toString()) .andExpect(MockMvcResultMatchers.redirectedUrl("/index")) // contacts = contactService.listContact() // id assert contacts assert contacts[0].id // , contactService.removeContact(contacts[0].id) }
@RequestMapping("/delete/{contactId}") public String deleteContact(@PathVariable("contactId") Integer contactId) { contactService.removeContact(contactId); return "redirect:/index"; }
@PathVariable
also not a problem, just add it to the URL. @Test public void delete() { // def contactTypes = contactService.listContactType() assert contactTypes Contact contact = new Contact( firstname : 'firstname', lastname : 'lastname', email : 'firstname.lastname@gmail.com', telephone : '555-1234', contacttype : contactTypes[0] ) contactService.addContact(contact) assert contact.id def contacts = contactService.listContact() // contacts.id id assert contact.id in contacts.id // POST- , URL id // ${contact.id} - placeholder, GString! mockMvc.perform(MockMvcRequestBuilders.get("/delete/${contact.id}") .andExpect(MockMvcResultMatchers.redirectedUrl("/index")) // , def contacts = contactService.listContact() assert !(contact.id in contacts.id) }
security.xml
if there is no mention of users and roles in the tests? And he will be right. In the third part of the lesson, we will add support for working with SpringSecurity.addFilter()
, in which we can pass an instance of springSecurityFilterChain
. Let's change our test as follows: @Autowired FilterChainProxy springSecurityFilterChain @Before public void setup() { this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac) .addFilter(springSecurityFilterChain) // .dispatchOptions(true).build() }
List<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("ROLE_USER"); Authentication auth = new UsernamePasswordAuthenticationToken("user1", "1111", authorities); SecurityContextHolder.getContext().setAuthentication(auth);
DEBUG: org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Secure object: FilterInvocation: URL: /add; Attributes: [ROLE_USER] DEBUG: org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Previously Authenticated: org.springframework.security.authentication. AnonymousAuthenticationToken@d4551ca6: Principal: guest; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication. WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS DEBUG: org.springframework.security.web.access.ExceptionTranslationFilter - Access is denied (user is anonymous); redirecting to authentication entry point
Granted Authorities: ROLE_ANONYMOUS
hints that our feint didn’t work with our ears. But I hasten to reassure - our guilt is not here, supporting Security in the tests has not yet been implemented . That is why in the beginning I wrote that integration with SpringSecurity is “almost no problem”. The problem is still there, but it is solved.src/test/java
folder and show how it can be used for our needs.setAuthentication(auth)
, which turned out to be useless, and in the add () method we add one line to the query construct: //... mockMvc.perform(MockMvcRequestBuilders.post("/add") .param("firstname",'firstname') .param("lastname",'lastname') .param("email",'firstname.lastname@gmail.com') .param("telephone",'555-1234') .param("contacttype.id", contactTypes[0].id.toString()) .with(SecurityRequestPostProcessors.userDetailsService("user1"))) // Security .andExpect(MockMvcResultMatchers.redirectedUrl("/index")) // ...
Granted Authorities: ROLE_USER
result.andExpect(MockMvcResultMatchers.redirectedUrl("http://localhost/login.jsp"))
mockMvc.perform(MockMvcRequestBuilders.get("/delete/1") .with(SecurityRequestPostProcessors.userDetailsService("user1"))) .andExpect(MockMvcResultMatchers.forwardedUrl("/error403.jsp"))
Source: https://habr.com/ru/post/171911/
All Articles