Reputation: 1174
I have two projects. One called myCore
and one called myWeb
. myCore
contains all of the beans and repository interfaces. myWeb
is simply a JSON api that brings in myCore
as a dependency. When I run myWeb
everything works fine. When I try to run unit tests against the controllers in myWeb
the @Autowired
repos are null
. I need to find some way for the @Autowired
repository interfaces to have the same value as when the application is running, or to mock those objects. Preferably I would like to know how to implement both solutions.
myCore pom.xml
:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>2.12.4</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>1.6.1.RELEASE</version>
</dependency>
myCore
context.xml
<mongo:repositories base-package="com.myOrg.myapp.repo.mongo" />
<mongo:db-factory id="dbfactory" host="removed"
port="removed" dbname="removed" username="removed" password="removed" />
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg name="mongoDbFactory" ref="dbfactory" />
</bean>
repo interface:
public interface SiteRepository extends PagingAndSortingRepository<Site, String>{
void findBySomethingCustom(String somethingCustom);
}
In the web project: 'myWeb` pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<start-class>com.myOrg.myApp.Application</start-class>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.myOrg</groupId>
<artifactId>myCore</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
myWeb
config:
@Configuration
@ImportResource("classpath*:/spring/context.xml")
public class Config {}
myWeb
controller:
@RestController
@RequestMapping("site")
public class SiteController {
@Autowired
private SiteRepository siteRepo;
@RequestMapping(value = "", method = RequestMethod.GET)
public Iterable<Site> getSites() {
return siteRepo.findAll();
}
}
And finally, the test class:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MockServletContext.class)
@WebAppConfiguration
@ContextConfiguration(classes = Config.class)
public class SiteControllerTest {
private MockMvc mvc;
@Before
public void setUp() throws Exception {
mvc = MockMvcBuilders.standaloneSetup(new SiteController()).build();
}
@Test
public void testGetSites() throws Exception {
mvc.perform(
MockMvcRequestBuilders.get("/site"));
}
}
I am getting a null pointer exception in testGetSites() that indicates siteRepo is null. However, navigating to the url of that controller method executes normally.
Again, I either need that to have the value it has when the application runs normally, and/or a way to mock that object so the test can pass(or fail) normally.
UPDATE
Changed
mvc = MockMvcBuilders.standaloneSetup(new SiteController()).build();
to
mvc = MockMvcBuilders.webAppContextSetup(wac).build();
where wac
references
@Autowired
private WebApplicationContext wac;
Also changed:
@SpringApplicationConfiguration(classes = {MockServletContext.class}
to
@SpringApplicationConfiguration(classes = {Application.class})
Upvotes: 2
Views: 2678
Reputation: 4683
I believe NPE is cause by mvc = MockMvcBuilders.standaloneSetup(new SiteController())
. Javadoc says:
This allows full control over the instantiation and initialization of controllers, and their dependencies, similar to plain unit tests while also making it possible to test one controller at a time.
In my interpretation it means that your are responsible for providing all dependencies (e.g. you can provide mocks etc). And since you have just created new instance without any dependencies, you got NPE.
So I see two solution:
Provide your own mocked dependencies
Use webAppContextSetup.webAppContextSetup
instead if you want spring resolve dependecies for you.
Upvotes: 3