Spring testing and maven

2020-03-25 16:09发布

问题:

I'm trying to test my Spring web app but i have some problems.

I added a test class in my maven

@RunWith( SpringJUnit4ClassRunner.class )
@ContextConfiguration
public class UserServiceTest {

    @Autowired
    private UserService userService;

    @Test
    public void testName() throws Exception {
        List<UserEntity> userEntities = userService.getAllUsers();

        Assert.assertNotNull(userEntities);
    }
}

But i got a NullPointerException on userService when i try to run this test. IntelliJ say "Could not autowire. No beans of 'UserService' type found. After adding @RunWith(SpringJUnit4ClassRunner.class) , i got this exception

java.lang.IllegalStateException: Neither GenericXmlContextLoader nor AnnotationConfigContextLoader was able to detect defaults, and no ApplicationContextInitializers were declared for context configuration

How can i solve it ? And i think i need to run this test on my tomcat server but how can i deploy for testing with IntelliJ ? (like command 'mvn clean install tomcat7:run-war-only')

回答1:

You have to provide the location of your Spring context file to be initialized before the test starts.

Test class

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

    @Autowired
    private UserService userService;

    @Test
    public void testName() throws Exception {
        List<UserEntity> userEntities = userService.getAllUsers();

        Assert.assertNotNull(userEntities);
    }
}

your-spring-context.xml

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

    <bean id="userService" class="java.package.UserServiceImpl"/>

</beans>


回答2:

Depending on what you are trying to achieve via testing, you need to either write a unit test or a Spring integration test.

In the latter case you need to change your code to:

@ContextConfiguration(locations = {"classpath:/applicationContext.xml"})
@RunWith(SpringJUnit4ClassRunner.class)
public class UserServiceTest {

   @Autowired
   private UserService userService;

    //test whatever
}

When performing such integration tests, you will probably want to hook into the Spring Profile mechanism. By leveraging it, you will be able to reuse the same configuration you use in your production code while selectively replacing certain beans (for example by swapping the production datasource with an in-memory database).

If you are using Spring 4, then Conditional would give you even more flexibility.

I suggest you give this part of the Spring test documentation a good read to get an overview of what Spring integration tests can do for you.


The case you have presented I'm not sure warrants itself for an integration test (more details on what UserService actually does would give a clearer picture).

For example if UserService uses a UserDao and then performs some custom logic on the results from the dao, creating a unit test for UserService with a mocked UserDao would be a good option.

If you are using constructor injection to supply the dao to the service, then construction of the service is a no-brainer. If you are using field injection via @Autowired (which you shouldn't be if you can avoid it), then you would need to inject the mock via reflection. A super utility for that is Spring's ReflectionTestUtils

Then you could create an integration test for UserDao which would test it's ability to correctly read data from the database.


Finally note that the comments above are independent of the how you run the tests (IDE or Maven). If it's configured correctly, the tools will happilly run it



回答3:

I am not sure, but think that you need to add locations property to ContextConfiguration annotation where you could specify the xml file where all of the beans exist. Moreover, I guess the operation of fetching all users is database related so it is good to add TransactionConfiguration annotation. Thus, you should have something like this:

@ContextConfiguration(locations = {"classpath:spring-config-junit.xml"}) @TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)