77

I test the following DAO with JUnit:

@Repository
public class MyDao {

    @Autowired
    private SessionFactory sessionFactory;

    // Other stuff here

}

As you can see, the sessionFactory is autowired using Spring. When I run the test, sessionFactory remains null and I get a null pointer exception.

This is the sessionFactory configuration in Spring:

<bean id="sessionFactory"
    class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="configLocation">
        <value>classpath:hibernate.cfg.xml</value>
    </property>
    <property name="configurationClass">
        <value>org.hibernate.cfg.AnnotationConfiguration</value>
    </property>
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">${jdbc.dialect}</prop>
            <prop key="hibernate.show_sql">true</prop>
        </props>
    </property>
</bean>

What's wrong? How can I enable autowiring for unit testings too?

Update: I don't know if it's the only way to run JUnit tests, but note that I'm running it in Eclipse with right-clicking on the test file and selecting "run as"->"JUnit test"

Thermech
  • 4,371
  • 2
  • 39
  • 60
user1883212
  • 7,539
  • 11
  • 46
  • 82

6 Answers6

44

Add something like this to your root unit test class:

@RunWith( SpringJUnit4ClassRunner.class )
@ContextConfiguration

This will use the XML in your default path. If you need to specify a non-default path then you can supply a locations property to the ContextConfiguration annotation.

http://static.springsource.org/spring/docs/2.5.6/reference/testing.html

robert_difalco
  • 4,821
  • 4
  • 36
  • 58
  • 1
    I can't see and include these annotations – user1883212 Jul 12 '13 at 21:02
  • Ok I just needed to add something into the pom in order to be able to use the annotation. Now that I added them I get this error: java.lang.IllegalStateException: Neither GenericXmlContextLoader nor AnnotationConfigContextLoader was able to detect defaults, and no ApplicationContextInitializers were declared for context configuration [ContextConfigurationAttributes@1dd58d8 declaringClass = 'org.davis.dao.EmployeeDAOImplTest', locations = '{}', classes = '{}', inheritLocations = true, initializers = '{}', inheritInitializers = true, name = [null], contextLoaderClass = 'org.springframework.t... – user1883212 Jul 12 '13 at 21:12
  • Right, add the locations property to your ContextConfiguration annotation and supply the path to your XML file per the spring documentation I gave you. – robert_difalco Jul 12 '13 at 21:13
  • I tryed with this, is it correct? @ContextConfiguration(locations={"/WEB-INF/spring-servlet.xml"}) – user1883212 Jul 12 '13 at 21:18
  • I can't tell you if it is correct. For my project I specify it as: locations = "classpath:/META-INF/spring/applicationContext.xml" – robert_difalco Jul 12 '13 at 21:25
  • For me i worked just by adding `@RunWith( SpringJUnit4ClassRunner.class )` in spring-boot – comiventor Apr 04 '18 at 20:28
  • @user1883212 for that message see https://stackoverflow.com/questions/26055876/spring-testing-and-maven – rogerdpack Oct 29 '20 at 19:45
26

I had same problem with Spring Boot 2.1.1 and JUnit 4
just added those annotations:

@RunWith( SpringRunner.class )
@SpringBootTest

and all went well.

For Junit 5:

@ExtendWith(SpringExtension.class)

source

Mcin
  • 354
  • 4
  • 5
22

I'm using JUnit 5 and for me the problem was that I had imported Test from the wrong package:

import org.junit.Test;

Replacing it with the following worked for me:

import org.junit.jupiter.api.Test;
Caner
  • 57,267
  • 35
  • 174
  • 180
9

You need to use the Spring JUnit runner in order to wire in Spring beans from your context. The code below assumes that you have a application context called testContest.xml available on the test classpath.

import org.hibernate.SessionFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;

import java.sql.SQLException;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.startsWith;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath*:**/testContext.xml"})
@Transactional
public class someDaoTest {

    @Autowired
    protected SessionFactory sessionFactory;

    @Test
    public void testDBSourceIsCorrect() throws SQLException {
        String databaseProductName = sessionFactory.getCurrentSession()
                .connection()
                .getMetaData()
                .getDatabaseProductName();
        assertThat("Test container is pointing at the wrong DB.", databaseProductName, startsWith("HSQL"));
    }
}

Note: This works with Spring 2.5.2 and Hibernate 3.6.5

Rylander
  • 19,449
  • 25
  • 93
  • 144
  • The problem is to understand the right path to use. I have my servlet-context.xml under src/main/webapp/WEB-INF/spring-servlet.xml and I'm using this location: @ContextConfiguration(locations = {"classpath:spring-servlet.xml"}) But this doesn't work. What should I write instead? – user1883212 Jul 12 '13 at 22:41
  • 1
    @user1883212 Try `@ContextConfiguration(locations = { "classpath*:**/servlet-context.xml" })` – Rylander Jul 15 '13 at 15:00
  • @user1883212 using `classpath*:**/.xml` will search for a context anywhere on your classpath. Is you bean defined in your context or in a servlet? – Rylander Jul 15 '13 at 15:06
6

Missing Context file location in configuration can cause this, one approach to solve this:

  • Specifying Context file location in ContextConfiguration

like:

@ContextConfiguration(locations = { "classpath:META-INF/your-spring-context.xml" })

More details

@RunWith( SpringJUnit4ClassRunner.class )
@ContextConfiguration(locations = { "classpath:META-INF/your-spring-context.xml" })
public class UserServiceTest extends AbstractJUnit4SpringContextTests {}

Reference:Thanks to @Xstian

Community
  • 1
  • 1
Abhijeet
  • 8,561
  • 5
  • 70
  • 76
3

You need to add annotations to the Junit class, telling it to use the SpringJunitRunner. The ones you want are:

@ContextConfiguration("/test-context.xml")
@RunWith(SpringJUnit4ClassRunner.class)

This tells Junit to use the test-context.xml file in same directory as your test. This file should be similar to the real context.xml you're using for spring, but pointing to test resources, naturally.

TrueDub
  • 5,000
  • 1
  • 27
  • 33