0

I am testing a simple method of my controller. The issue is that, the controller has a service and the service class has a repository. Having all this, I suppose I would need to Mock all the classes. Am I right?

I can easily run the application but when I run the test it shows following exception. How can I bypass that to test method of controller?

java.lang.IllegalStateException: Failed to load ApplicationContext
....

Caused by: org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'userRepositoryImpl': 
Injection of autowired dependencies failed; nested exception is 
org.springframework.beans.factory.BeanCreationException: 
Could not autowire field: 
private org.hibernate.SessionFactory  
com.myproject.repository.UserRepositoryImpl.sessionFactory; 
nested exception is
org.springframework.beans.factory.BeanCreationException: Error 
creating bean with name 'sessionFactory' defined in class path res
ource [main/my-servlet.xml]:
Invocation of init method failed; nested exception is 
org.hibernate.HibernateException: Connection cannot be null when 
'hibernate.dialect' not set
...

Caused by: org.springframework.beans.factory.BeanCreationException: 
Could not autowire field: private org.hibernate.SessionFactory 
com.myproject.repository.UserRepositoryImpl.sessionFactory; nested 
exception is org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'sessionFactory' defined in class
....

Caused by: org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'sessionFactory' defined in class path 
resource [main/my-servlet.xml]: Invocation of init method failed; 
nested exception is org.hibernate.HibernateException: Connection 
cannot be null when 'hibernate.dialect' not set
....

Caused by: org.hibernate.HibernateException: Connection cannot be 
null when 'hibernate.dialect' not set

JUnit code

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration({"classpath:main/my-servlet.xml"})
public class UserControllerTest {
    @Autowired
    WebApplicationContext wac;
    private MockMvc mockMvc;

    @Before
    public void setup() {
        mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
    }

    @Test
    public void shouldReturnUsersViewName() throws Exception {


        UserService mockedUsrSer = Mockito.mock(UserService.class);

        UserController controller = new UserController(mockedUsrSer);
        this.mockMvc.perform(get("/")).andExpect(view().name("users"));

    }

Controller

private UserService userService;

@Autowired
public UserController(UserService userService) {
    super();
    this.userService = userService;
}

@RequestMapping(value = { "", "/"}, method = RequestMethod.GET)
public String showUsers(Model model) {
    return "users";
}

Service

@Service
public class UserServiceImpl implements UserService {

  private UserRepository userRepository;

  @Autowired
  public UserServiceImpl(UserRepository userRepository){
    this.userRepository = userRepository;
  }
  ....
}

Repository

 @Repository
 public class UserRepositoryImpl implements UserRepository{

  private SessionFactory sessionFactory;

  @Autowired
  public UserRepositoryImpl(SessionFactory sessionFactory){
     this.sessionFactory = sessionFactory;
  }
  ...
 }

my-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">

    <context:annotation-config />

    <mvc:annotation-driven />

    <context:component-scan base-package="com.myProject" />

    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.tiles3.TilesViewResolver" />
    <bean id="tilesConfigurer"
        class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
        <property name="definitions">
            <list>
                <value>/WEB-INF/tiles.xml</value>
            </list>
        </property>
    </bean>

    <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"
        destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://localhost:2005/Test" />
        <property name="username" value="jack" />
        <property name="password" value="jack" />
    </bean>


     <bean id="sessionFactory" 
    class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" 
     depends-on="dataSource"> 
     <property name="dataSource" ref="dataSource" />
     <property name="packagesToScan" value="com.myProject.model" /> 
    <property name="hibernateProperties"> 
     <props> 
    <prop key="hibernate.format_sql">true</prop> 
    <prop key="hibernate.use_sql_comments">true</prop>
    <prop key="hibernate.show_sql">true</prop> 
     <prop key="hibernate.hbm2ddl.auto">update</prop>
     </props> 
    </property> 
    </bean> 

     <bean 
    class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" 
        /> 

     <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> 
    <property name="sessionFactory" ref="sessionFactory" /> 
     </bean> 

    <tx:annotation-driven transaction-manager="transactionManager" /> 
</beans>

Update

I commented out all of the hibernate related lines in my-servlet.xml file, but the test returns an exception as follows:

No qualifying bean of type [org.hibernate.SessionFactory] found for dependency
11
  • No, you're not in a context that you would want to mock these things out. Have you checked whether or not your connection details are null?
    – Makoto
    Commented Sep 21, 2015 at 23:41
  • @Makoto they should not be because I can run the application with current configuration. If I should not mock UserService class then how to run the test?
    – Jack
    Commented Sep 21, 2015 at 23:50
  • You've got to fix the wiring. Something's amiss with it.
    – Makoto
    Commented Sep 22, 2015 at 0:04
  • @Makoto what do you mean by fixing the wiring? The application is properly working.
    – Jack
    Commented Sep 22, 2015 at 0:05
  • The application may be working, but in a test context, your beans are not being properly wired. Without seeing how they're wired in the first place, it's tough to say what's wrong, but I'd start there. Be sure that, in a test context, what you expect to be wired in is what is actually wired in.
    – Makoto
    Commented Sep 22, 2015 at 0:15

2 Answers 2

2

I think you should create a stripped-down version of my-servlet.xml and use that for testing. It should only component-scan the controller package. You can also inject a mock UserService to the controller as follows.

<context:annotation-config />

<mvc:annotation-driven />

<context:component-scan base-package="com.myProject.controller" />

<bean id="viewResolver"
    class="org.springframework.web.servlet.view.tiles3.TilesViewResolver" />
<bean id="tilesConfigurer"
    class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
    <property name="definitions">
        <list>
            <value>/WEB-INF/tiles.xml</value>
        </list>
    </property>
</bean> 

<bean id="userService" class="org.mockito.Mockito" factory-method="mock"> 
    <constructor-arg value="com.myproject.service.UserService" /> 
</bean>

Another option is to use standaloneSetup.

@RunWith(SpringJUnit4ClassRunner.class)
public class UserControllerTest {

@Mock
private UserService userService;

@InjectMocks
private UserController userController;

private MockMvc mockMvc;

@Before
public void setup() {

    // Setup Spring test in standalone mode
    this.mockMvc = MockMvcBuilders.standaloneSetup(userController).build();

}
}
3
  • It did not work as it is expecting ApplicationContext so I added following annotation to the class @ContextConfiguration({ "classpath:main/my-servlet.xml" }), then it threw following exception 'Failed to load ApplicationContext' Caused by: Error creating bean with name 'tilesConfigurer'. I removed tiles configuration from servlet but it throws NullPointerException!!!
    – Jack
    Commented Sep 23, 2015 at 0:00
  • When using standaloneSetup(...) you do not need to use the SpringJUnit4ClassRunner. Therefore, you also do not need @ContextConfiguration. Commented Sep 23, 2015 at 14:45
  • I had a similar problem loading mocked Repositories. Using "MockMvcBuilders.standaloneSetup(...)" was what I was missing. Thanks.
    – Pytry
    Commented Oct 19, 2015 at 22:20
0

I agree with user2953113's suggestion, that would likely work. However, I try to avoid any XML in my unit tests (functional testing is a different matter but I wouldn't mock out the UserService in a functional test). I haven't used Spring MVC much but could you do this? Not sure you would even need the SprintJUnit4ClassRunner in this case.

public class UserControllerTest {

    @Before
    public void setup() {

        UserService mockedUsrSer = Mockito.mock(UserService.class);
        UserController controller = new UserController(mockedUsrSer);
        MockMvc mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
        mockMvc.perform(get("/")).andExpect(view().name("users"));

    }
}
5
  • It runs into java.lang.illegalStateException: Failed to load ApplicationContext
    – Jack
    Commented Sep 22, 2015 at 23:40
  • Also, perfom method throws Exception that need to be caught.
    – Jack
    Commented Sep 22, 2015 at 23:41
  • You do not need to use the SpringJUnit4ClassRunner in this scenario. Commented Sep 23, 2015 at 14:43
  • Do not catch the exception. Catching exceptions in tests is essentially an anti-pattern. Instead, just add throws Exception to any @Before, @After, or @Test method. Commented Sep 23, 2015 at 14:44
  • Removed the SpringJUnit4ClassRunner. Was that causing it to try and load an ApplicationContext? I'm not sure where else it would be doing that.
    – Pace
    Commented Sep 23, 2015 at 16:43

Not the answer you're looking for? Browse other questions tagged or ask your own question.