I am trying to implement a simple test for Java Spring Framework. Below is my code.
My Controller:
#RequestMapping(value = "/someMapping", method = RequestMethod.GET)
public String toTestMethod(Model model)
{
model.addAttribute("test", 1);
return "test";
}
Controller Test:
#Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
#Before
public void setup()
{
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
#Test
public void testMethodTest() throws Exception
{
this.mockMvc.perform(get("/someMapping"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(model().attribute("test", 1));
}
Application context:
#Configuration
#EnableWebMvc
public class WebAppContext extends WebMvcConfigurerAdapter
{
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry)
{
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer)
{
configurer.enable();
}
#Bean
public ViewResolver viewResolver()
{
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/jsp/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
When I run this test, it fails with the following exception
java.lang.AssertionError: Model attribute 'test' expected:<1> but was:<null>.
I have no idea why this happens, can someone please clarify?
If needed, I will provide any additional information.
So, in my case the problem was in the setup(), now it looks like this:
#Before
public void setup()
{
// this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
MyController ctrl = new MyController();
this.mockMvc = MockMvcBuilders.standaloneSetup(ctrl).build();
}
It started working as expected after this change.
Related
I have next project structure:
WebMvcConfiguration class:
#Configuration
#EnableWebMvc
#ComponentScan("com.test.controller")
public class WebMvcConfiguration {
#Bean
public InternalResourceViewResolver resolver() {
return new InternalResourceViewResolver("/WEB-INF/view/", ".html");
}
}
WebAppInitializer class:
public class WebAppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) {
AnnotationConfigWebApplicationContext webApplicationContext = new AnnotationConfigWebApplicationContext();
webApplicationContext.scan("com.test.configuration");
webApplicationContext.setServletContext(servletContext);
ServletRegistration.Dynamic servletDispatcher =
servletContext.addServlet("dispatcher", new DispatcherServlet(webApplicationContext));
servletDispatcher.setLoadOnStartup(1);
servletDispatcher.addMapping("/");
}
}
CustomRestController class:
#RestController
public class CustomRestController {
#GetMapping(value = "/rest", produces = MediaType.TEXT_PLAIN_VALUE)
public String main() {
return "main";
}
}
CustomPageController class:
#Controller
public class CustomPageController {
#GetMapping("/page")
public String main() {
return "main";
}
}
Rest controller work as it should. But PageController fails with this Exception:
org.springframework.web.servlet.DispatcherServlet.noHandlerFound No mapping for GET /WEB-INF/view/main.html
I forgot to enable DefaultServletHandlerConfigurer in WebMvcConfiguration:
#Configuration
#EnableWebMvc
#ComponentScan("com.test.controller")
public class WebMvcConfiguration implements WebMvcConfigurer {
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
#Bean
public InternalResourceViewResolver resolver() {
return new InternalResourceViewResolver("/WEB-INF/view/", ".html");
}
}
I have a class called SomeBean and two tests that are configured with Stubs for different scenarios. I am using Spring Boot.
The second test is supposed to pass without Exception because there is no stubbing that I did to throw Exception.
The DirtiesContext is not working as well. If I remove the commented code in Test2.java I get the test to pass. I would like to remove the unnecessary subbing by using something similar to DirtiesContext.
I may be missing something basic. Can someone point to what I am doing incorrect.
#Service
public class SomeBeanProcessor {
#Autowired
private BeanValidator beanValidator;
public ResultBean process(SomeBean sb) throws ValidationException{
beanValidator.validateBean(sb);
//Do some processing and return ResultBean;
}
}
Test1.java
RunWith(SpringRunner.class)
#SpringBootTest(classes = {MyApp.class})
#WebAppConfiguration
#ContextConfiguration(classes=Test1.Test1Config.class) {
public class Test1 {
#Configuration
static class Test1Config {
#Bean
public BeanValidator getSomeRequestValidator() {
return new BeanValidator() {
public void validateBean(SomeBean bean) throws ValidationException {
throw new ValidationException("Validation failed");
}
};
}
}
#Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
#Autowired
private SomeBeanProcessor aBeanProcessor;
#Before
public void setUp() {
mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
}
#Test
#DirtiesContext
public void doTestValidationErrors() throws ValidationException{
SomeBean sb = new SomeBean();
this.aBeanProcessor.process(sb);
Assert.fail("Should throw exception");
}
}
Test2.java
RunWith(SpringRunner.class)
#SpringBootTest(classes = {MyApp.class})
#WebAppConfiguration
#ContextConfiguration(classes=Test2.Test2Config.class) {
public class Test2 {
#Configuration
static class Test2Config {
//#Bean
//public BeanValidator getSomeRequestValidator() {
// return new BeanValidator() {
// public void validateBean(SomeBean bean) throws ValidationException { //Do nothing
// }
// };
//}
}
#Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
#Autowired
private SomeBeanProcessor aBeanProcessor;
#Before
public void setUp() {
mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
}
#Test
#DirtiesContext
public void doTestSuccess() throws ValidationException{
SomeBean sb = new SomeBean();
this.aBeanProcessor.process(sb);
}
}
I am trying to Unit test a simple Spring-MVC-Controller but even the simplest Unit Test fails because a #ModelAttribute throws a NullpointerException. My Question is: How to mock/set the ModelAttribute?
I've tried mocking the findAll() method from the repository but it fails.
Below are my used classes:
TestContext:
#Configuration
public class TestContext {
#Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("i18n/messages");
messageSource.setUseCodeAsDefaultMessage(true);
return messageSource;
}
#Bean
public BenutzerRepository benutzerRepository() {
return Mockito.mock(BenutzerRepository.class);
}
}
StandaloneBenutzerController:
#RunWith(MockitoJUnitRunner.class)
#SpringApplicationConfiguration(TestContext.class)
public class StandaloneBenutzerControllerTest {
public MockMvc mockMvc;
#Mock
private BenutzerRepository benutzerRepositoryMock;
#Mock
private Benutzer benutzer;
#Before
public void setUp() {
this.benutzerRepositoryMock = Mockito.mock(BenutzerRepository.class);
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/jsp/");
viewResolver.setSuffix(".jsp");
Benutzer hauke = new Benutzer("test","tester", "test#tester.de");
List<Benutzer> mockList = new ArrayList<Benutzer>();
mockList.add(hauke);
mockMvc = MockMvcBuilders.standaloneSetup(new BenutzerController()).setViewResolvers(viewResolver)
.build();
}
#Test
public void testSimpleStatus() throws Exception {
Mockito.when(benutzer.getEmail()).thenReturn("test#tester.de");
//Mockito.when(benutzerRepositoryMock.findAll()).thenCallRealMethod();
//Mockito.when(benutzerRepositoryMock.findAll()).thenReturn(userList);
this.mockMvc.perform(get("/verwaltung"))
.andExpect(status().isOk())
.andExpect(forwardedUrl("/WEB-INF/jsp/verwaltung.jsp"));
}
}
BenutzerController: the Part which throws the Nullpointer
#ModelAttribute("userList")
public List<Benutzer> userList() {
return toList(repository.findAll());
}
The solution is like Si mo hinted to set the mock repository for the tested BenutzerController via the constructor:
mockMvc = MockMvcBuilders.standaloneSetup( new BenutzerController(benutzerRepositoryMock)).setViewResolvers(viewResolver).build();
I try to make my test to work with Spring #Transactional annotation.
#ContextConfiguration(classes = SomeTest.SomeTestSpringConfig.class)
#RunWith(SpringJUnit4ClassRunner.class)
public class SomeTest {
#Autowired
MyBean some;
#Autowired
PlatformTransactionManager transactionManager;
#Test
public void testSpring() throws Exception {
some.method();
assertTrue(some.isTransactionalWorks);
}
#EnableAspectJAutoProxy(proxyTargetClass = true)
#EnableLoadTimeWeaving
#EnableTransactionManagement(mode = AdviceMode.ASPECTJ)
#TransactionConfiguration
static class SomeTestSpringConfig {
#Bean
PlatformTransactionManager transactionManager() {
return new MyTransactionManager(dataSource());
}
#Bean
MyBean some() {
return new MyBean();
}
#Bean
DataSource dataSource() {
return new SimpleDriverDataSource(Driver.load(), "jdbc:h2:mem:unit-test");
}
}
}
class MyBean {
#Autowired
DataSource dataSource;
public boolean isTransactionalWorks;
#Transactional
private void someInTransaction() {
try {
dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
System.out.println("I should be in transaction");
}
public void method() {
someInTransaction();
}
}
class MyTransactionManager implements PlatformTransactionManager, InitializingBean {
private final DataSourceTransactionManager base = new DataSourceTransactionManager();
#Autowired
MyBean some;
public MyTransactionManager(DataSource datasource) {
base.setDataSource(datasource);
}
#Override
public TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
some.isTransactionalWorks = true;
return base.getTransaction(definition);
}
#Override
public void commit(TransactionStatus status) throws TransactionException {
base.commit(status);
}
#Override
public void rollback(TransactionStatus status) throws TransactionException {
base.rollback(status);
}
#Override
public void afterPropertiesSet() throws Exception {
base.afterPropertiesSet();
}
}
Also I added -javaagent:D:/libs/spring-instrument-4.1.7.RELEASE.jar to VM options for this test.
But it always fails. What did I miss?
Please check this link, i think it is the similar problem u are facing.
How to configure AspectJ with Load Time Weaving without Interface
In this link he has asked to provide both aspectjweaver.jar and spring-instrument.jar in vm argument.
Good to know it worked. :)
I have spring mvc project and i don't use #Autowired because my object always is null. How me load JavaConfig for using #Autowired, i do not use any *.xml file.
This is my controller with #Autowired field for service.
#Controller
public class WebController {
#Autowired
private ServiceWeb serviceWeb;
public void setServiceWeb(ServiceWeb serviceWeb) {
this.serviceWeb = serviceWeb;
}
...
}
This is my AbstractAnnotationConfigDispatcherServletInitializer
public class ServletInit extends
AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { SpringRootConfig.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { SpringWebConfig.class};
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
SpringRootConfig & SpringWebConfig
#Configuration
#ComponentScan({"web.controller"})
public class SpringRootConfig {
}
#EnableWebMvc
#Configuration
#ComponentScan({ "web.controller"})
#Import({SecurityConfig.class})
public class SpringWebConfig extends WebMvcConfigurerAdapter{
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/resources/");
}
#Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver viewResolver
= new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/jsp/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
Class for #Autowiring
#Configuration
public class ConfigurationBean {
#Bean
public ServiceWeb serviceWeb(){
return new ServiceWebImpl();
}
}
Register context for spring, but where need write Init.class for loading this config ?
public class Init implements WebApplicationInitializer {
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(ConfigurationBean.class);
servletContext.addListener(new ContextLoaderListener(ctx));
ctx.setServletContext(servletContext);
}
}
Pls try this...
#Service
public class ServiceWebImpl implements ServiceWeb {
}
ServiceWeb bean is created inside ConfigurationBean class and its not visible at spring context level for autowiring.