我有一个用于注册和登录的休息资源。两者都在控制器类中。控制器类依赖于具有业务逻辑的服务类。服务类具有进一步的依赖性。因为我使用嵌入式数据库进行测试,我想使用我的应用程序的真实依赖项,而不是像@injectmock @mock那样模拟它们。只有一种依赖我必须嘲笑。它是在注册过程后发送电子邮件的依赖项。如何编写带有@autowired函数的测试用例和一个用于电子邮件通知的特定模拟依赖项?
@Controller
public class AccountCommandsController {
@Autowired
private LogoutService service;
@RequestMapping(value = "/rest/login", method = RequestMethod.POST)
public ResponseEntity login(@RequestBody Account account) {
AccountLoginEvent accountLoginEvent = service.loginAccount(new RequestAccountLoginEvent(account.getEmailAddress(), account.getPassword()));
if (accountLoginEvent.isLoginGranted()) {
return new ResponseEntity(HttpStatus.ACCEPTED);
} else {
return new ResponseEntity(HttpStatus.UNAUTHORIZED);
}
}
@RequestMapping(value = "/rest/signup", method = RequestMethod.POST)
public ResponseEntity signup(@RequestBody Account account) {
AccountSignupEvent signedupEvent = service.signupAccount(new RequestAccountSignupEvent(account.getEmailAddress(), account.getPassword()));
if (signedupEvent.isSignupSuccess()) {
return new ResponseEntity(HttpStatus.ACCEPTED);
} else if (signedupEvent.isDuplicateEmailAddress()) {
return new ResponseEntity(HttpStatus.CONFLICT);
} else if (signedupEvent.isNoSignupMailSent()) {
return new ResponseEntity(HttpStatus.SERVICE_UNAVAILABLE);
} else {
return new ResponseEntity(HttpStatus.FORBIDDEN);
}
}
}
@Service
public class LogoutService {
@Autowired
private AccountsRepository accountsRepository;
@Autowired
private MailService mailService;
@Autowired
private HashService hashService;
public AccountSignupEvent signupAccount(RequestAccountSignupEvent signupEvent) {
if (accountsRepository.existEmailAddress(signupEvent.getEmailAddress())) {
return AccountSignupEvent.duplicateEmailAddress();
}
Account newAccount = new Account();
newAccount.setCreated(new Date());
newAccount.setModified(new Date());
newAccount.setEmailAddress(signupEvent.getEmailAddress());
newAccount.setPassword(signupEvent.getPassword());
newAccount.setVerificationHash(hashService.getUniqueVerificationHash());
SignupMailEvent mailSentEvent = mailService.sendSignupMail(new RequestSignupMailEvent(newAccount));
if (!mailSentEvent.isMailSent()) {
return AccountSignupEvent.noMailSent();
}
Account persistedAccount = accountsRepository.persist(newAccount);
return AccountSignupEvent.accountCreated(persistedAccount);
}
public AccountLoginEvent loginAccount(RequestAccountLoginEvent loginEvent) {
if (accountsRepository.existLogin(loginEvent.getEmailAddress(), loginEvent.getPassword())) {
return AccountLoginEvent.granted();
}
return AccountLoginEvent.denied();
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = TestConfiguration.class)
@Transactional
@TransactionConfiguration(defaultRollback = true)
public class LogoutTest {
private MockMvc mockMvc;
@Autowired
private AccountCommandsController controller;
@Before
public void setup() {
mockMvc = standaloneSetup(controller).build();
}
@Test
public void signupNoMail() throws Exception {
doReturn(AccountSignupEvent.noMailSent()).when(service).signupAccount(any(RequestAccountSignupEvent.class));
// when(controller.service.signupAccount(any(RequestAccountSignupEvent.class))).thenReturn(AccountSignupEvent.noMailSent());
mockMvc.perform(post("/rest/signup")
.content(new Gson().toJson(new Account(UUID.randomUUID().toString(), UUID.randomUUID().toString())))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isServiceUnavailable());
}
}
我希望你能看到问题所在。每个依赖工作正常而不是mailservice。我不想使用@injectmock和@mock和MockitoAnnotations.initMocks(this);在我的测试文件中,因为需要为所有依赖项提供模拟。
答案 0 :(得分:0)
如果您的依赖项正在运行并且您有一个已定义端点的配置类,则可以使用ConfigurableApplicationContext类,如下所示:
public class test {
private static ConfigurableApplicationContext appContext;
private LogoutService service;
@AfterClass
public static void destroy() {
appContext.close();
}
@Before
public void setup() {
appContext = new AnnotationConfigApplicationContext(YourClassConfig.class);
service = appContext.getBean(LogoutService.class);
}
@Test
public void beansAreCreated() {
assertNotNull(service);
}
}
或者您可以使用配置类重新编写端点,并且可以使用WireMock(http://wiremock.org)来模拟您对真实数据的依赖关系,这应该是这样的:
public class test {
@Rule
public WireMockRule wireMockRule = new WireMockRule(15000);
private static ConfigurableApplicationContext appContext;
private LogoutService service;
private static String serviceMockUrl;
@AfterClass
public static void destroy() {
appContext.close();
}
@Before
public void setup() {
serviceMockUrl = "http://localhost:" + wireMockRule.port();
appContext = new AnnotationConfigApplicationContext(TestConfig.class);
stubFor(get(urlEqualTo("urlToRequest")).
willReturn(aResponse().
withStatus(SC_OK).
withBody(createJsonArray("MapWithYourData").
withHeader("Content-Type", "application/json")));
service = appContext.getBean(LogoutService.class);
}
@Test
public void beansAreCreated() {
assertNotNull(service);
}
@Configuration
static class TestConfig {
@Bean
public PropertyPlaceholderConfigurer propertyPlaceholderConfigurer() {
return new PropertyPlaceholderConfigurer() {{
setProperties(new Properties() {{
setProperty("service.url", serviceMockUrl);
}});
}};
}
}
}
我希望这对你有所帮助。
答案 1 :(得分:0)
您尝试做的事情很容易使用Spring Profiles实现。
实现目标的方法如下:
@Configuration
public class TestConfiguration {
//this is the real mail service
@Bean
public MailService mailService() {
return new MailService(); //or whatever other bean creation logic you are using
}
//whatever else
}
@Configuration
@Profile("mockMail")
public class MockMailServiceConfig {
@Bean
@Primary
public MailService mockMailService() {
return mock(MailService.class);
}
}
您的测试类看起来像:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = TestConfiguration.class)
@Transactional
@TransactionConfiguration(defaultRollback = true)
@ActiveProfiles("mockMail")
public class LogoutTest {
//do your testing
}
请注意@Primary
中MockMailServiceConfig
的使用情况。我选择了这种方式,因为如果你还没有使用它们,它就不会要求你在其他任何地方引入配置文件。如果有多个候选人可用({在这种情况下有真正的邮件服务和模拟服务),@Primary
告诉spring使用该特定bean。