我想使用mockmvc
来测试Spring推荐的控制器。但是,我还必须使用jmockit
来模拟依赖性。
问题在于jmockit与mockmvc
无关,无论是standaloneSetup()
还是webAppContextSetup()
。
另一个名为Mockito的模拟工具已经完成了这个问题,但它在模拟依赖项方面有很多限制。
所以,任何人都有经验或想法,请告诉我。非常感谢你。
示例代码如下:
第一个是Mockito和Spring的MockMvc
单元测试控制器。运行良好。
public class TestControllerTest {
@InjectMocks
private LoginController loginController;
@Mock
private LoginService loginService;
private MockMvc mockMvc;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.standaloneSetup(loginController).build();
}
@Test
public void testLogin() throws Exception {
when(loginService.login()).thenReturn(false);
this.mockMvc.perform(get("/login"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(view().name("goodbyeworld"))
.andReturn();
}
}
其次,jmockit如下。不幸的是,loginController
在setup方法中为null。而且,如果我只是调用loginController.xxx()
方法中的@Tested
就可以了。我认为这表明loginController
方法在@Tested
方法之前但在@Before
方法之后被实例化。
public class TestControllerTest2 {
@Tested
private LoginController loginController;
@Injectable
private LoginService loginService;
private MockMvc mockMvc;
@Before
public void setUp() throws Exception {
this.mockMvc = MockMvcBuilders.standaloneSetup(loginController).build();
}
@Test
public void testLogin() throws Exception {
new Expectations() {{
loginService.login(); result = false;
}};
this.mockMvc.perform(get("/login"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(view().name("goodbyeworld"))
.andReturn();
}
}
那么,这个问题怎么解决? jmockit的少数初始化方法?有可能吗?
答案 0 :(得分:3)
与Mockito的@InjectMocks
不同,JMockit的@Tested
字段仅在执行任何@Before
方法后才会创建。这是因为测试方法中对模拟参数的支持,这在Mockito中并不存在。可以说,测试字段应该与模拟字段一起提前设置,因此这可能会在未来版本的JMockit中发生变化。
无论如何,现在问题的解决方案是:
@Tested
;相反,在@Before
方法中手动实例化并注入被测对象。@Tested
,但要避免依赖于测试字段的@Before
方法。在示例测试中,可以通过调用MockMvc
方法在每个测试方法中创建MockMvc mockMvc() { return MockMvcBuilders... }
对象。答案 1 :(得分:1)
问题是jmockit不能很好地使用mockmvc
我发现JMockit和Spring的MockMvc确实在一起玩得很好。我在我的案例中成功使用了webAppContextSetup。这是一个可能无法编译的示例,但可能是一个有用的指南,可以帮助您入门..
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import mockit.*;
import org.junit.*;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.WebApplicationContext;
import some.package.Account;
import some.package.Collaborator;
@RunWith(SpringJUnit4ClassRunner.class)
@Transactional
@WebAppConfiguration
@ContextConfiguration(locations = { "classpath:/context/example1.xml", "classpath:/context/example2.xml" })
public class AccountControllerIntegrationTest {
private static final String PATH_TO_ACCOUNT = "/accounts/some_account";
private String exampleAccountJson = "{\"account\":\"Sample\",\"active\":true}";
@Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
@Mocked
private Account mockAccount;
@Mocked
private Collaborator mockCollaborator;
@Before
public void setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
}
@Test
public void should_delete_account() throws Exception {
new Expectations() {{
mockAccount.getSomethingWhichReallyShouldNotBeExposed(); result = mockCollaborator;
mockCollaborator.getSomething(); result = "whatever";
}};
mockMvc.perform(delete(PATH_TO_ACCOUNT)).andExpect(status().isOk());
}
@Test
public void should_add_account() throws Exception {
new NonStrictExpectations() {{
mockAccount.getSomethingWhichReallyShouldNotBeExposed(); result = mockCollaborator;
mockCollaborator.getSomething(); result = "whatever";
}};
mockMvc.perform(put(PATH_TO_ACCOUNT).contentType(MediaType.APPLICATION_JSON).content(exampleAccountJson)).andExpect(status().isOk());
}
}
希望它可以帮到你 - 祝你好运!
答案 2 :(得分:1)
我最近遇到过类似的问题,我找到了一些优雅的解决方案:
@Tested(availableDuringSetup=true)
NotificationController notificationController;
@Injectable
NotificationService notificationService;
private MockMvc mockMvc;
@Before
public void init() {
this.mockMvc = MockMvcBuilders.standaloneSetup(notificationController).build();
}
boolean availableDuringSetup
注释的 @Tested
属性是解决方案:)
希望有所帮助,