在Spring4中使用具有某些模拟依赖项的自动连接依赖项

时间:2014-07-17 15:52:14

标签: java spring mockito

我有一个用于注册和登录的休息资源。两者都在控制器类中。控制器类依赖于具有业务逻辑的服务类。服务类具有进一步的依赖性。因为我使用嵌入式数据库进行测试,我想使用我的应用程序的真实依赖项,而不是像@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);在我的测试文件中,因为需要为所有依赖项提供模拟。

2 个答案:

答案 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
}

请注意@PrimaryMockMailServiceConfig的使用情况。我选择了这种方式,因为如果你还没有使用它们,它就不会要求你在其他任何地方引入配置文件。如果有多个候选人可用({在这种情况下有真正的邮件服务和模拟服务),@Primary告诉spring使用该特定bean。