What is the best way to test Controllers and Services with JUnit? - java

I have this Spring MVC controller:
#Controller
#RequestMapping(value = "/foo")
public class FooController {
#Inject
private FooService fooService;
#RequestMapping(value = "foo/new")
public final String add(final ModelMap model) {
model.addAttribute(fooService.createFoo());
return "foo/detail";
}
#RequestMapping(value = "foo/{id}")
public final String detail(final ModelMap model, #PathVariable long id) {
model.addAttribute(fooService.findById(id));
return "foo/detail";
}
#RequestMapping(value="foo/update", method=RequestMethod.POST)
public final String save(#Valid #ModelAttribute final Foo foo, final BindingResult result, final SessionStatus status,
final RedirectAttributes ra, final HttpServletRequest request) {
if (result.hasErrors()) {
return "foo/detail";
}
fooService.save(foo);
status.setComplete();
Message.success(ra, "message.ok");
return "redirect:foo/list";
}
#RequestMapping( value= "/foo/delete/{id}", method=RequestMethod.POST)
public String delete(#PathVariable final Long id, final SessionStatus status, final RedirectAttributes ra, final HttpServletRequest request){
if (fooService.findByIdWithOtherFoos(id).getOtherFoos().isEmpty()) {
fooService.delete(id);
status.setComplete();
MessageHelper.success(ra, "message.sucess");
} else {
Message.error(ra, "message.error");
}
return "redirect:foo/list";
}
}
And this Service:
#Service
#Transactional(readOnly = true)
public class FooServiceImpl implements FooService {
#Inject
private fooRepository fooRepo;
#Override
public final Foo createFoo() {
return new Foo();
}
#Override
#Transactional(readOnly = false)
public final void save(final Foo foo) {
if (foo.getId() == null) {
foo.setDate(new Date());
}
fooRepo.save(foo);
}
#Override
#Transactional(readOnly = false)
public final void delete(final Long id) {
fooRepo.delete(id);
}
#Override
public final Foo findById(final Long id) {
return fooRepo.findOne(id);
}
#Override
public Foo findByIdWithOtherFoos(Long id) {
Foo foo = fooRepo.findOne(id);
Hibernate.initialize(foo.getOtherFoos());
return foo;
}
#Override
public final Page<Foo> findAll(final Pageable pageable) {
return fooRepo.findAll(pageable);
}
#Override
public final Page<Foo> find(final String filter, final Pageable pageable) {
// TODO Auto-generated method stub
return null;
}
#Override
public final List<Foo> findAll(final Sort sort) {
return fooRepo.findAll(sort);
}
}
What is the best way of testing with JUnit drivers and services to cover all logical conditions?
I always end up with a bunch of test lines to cover all logical conditions.
We recommend using MockitoJUnitRunner? Or create classes which create configuration beans. And charge them with ContextConfiguration 'ContextConfiguration (FooServiceImplTestConfiguration.class classes = {})'
How to implement the Given-When-Then pattern?

When it comes to testing Controllers (especially integration testing) i suggest using Spring's MockMVC or Rest-Assured. And example of using Rest-Assured in action can be seen below:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = SomeApplication.class)
#WebIntegrationTest(randomPort = true)
#ActiveProfiles(profiles = "test")
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
public class SomeControllerTest {
#Test
public void getAllSomeObjects() {
expect().statusCode(HttpStatus.SC_OK)
.body("", hasSize(2))
.body("[0]", notNullValue())
.body("[1]", notNullValue())
.body("findAll { it.name.equals('TEST1') }", hasSize(1))
.body("findAll { it.name.equals('TEST2') }", hasSize(1))
.when()
.get("/someAddress");
}
}
For testing Services i suggest using Mockito. Additionally Hamcrest Matchers is a useful library for assertions in tests. Example of using both below:
public class SomeServiceTest {
#InjectMocks
private SomeService someService;
#Mock
private SomeInnerService someInnerService;
#Before
public void setUp() {
initMocks(this);
Mockito.when(someInnerService.useMethod("argument")).thenReturn(new SomeObject());
}
#Test
public void testSomeMethod() {
Set<SomeObject> someObjects= someService.someMethod();
assertThat(someObjects, is(notNullValue()));
assertThat(someObjects, is(hasSize(4)));
}
}

You should test both independently.
First create a unit test for your service. You can use Mockito to mock your service dependency as fooRepository.
#Test
public void testFindById() {
when(fooServices.findById(123)).thenReturn(fooSample);
assertThat(what you want);
}
Then, you should create an other unit test for your controller. The easiest way to do that is to use MockMvc provided in spring-test. And in this case, you can use Mockito to mock fooService.

Best Part. Use spring MVC test layer. As they are providing their own API's which helps you to mock controllers and provide you session objects which you can fill with required state. you can find lots of examples online.
http://www.petrikainulainen.net/spring-mvc-test-tutorial/
You can actually test all your layers seperately .. All the best !!

Have a look at Spring-Test-MVC. That's a framework for exactly that purpose and comes with a lot of easy to understand and rebuild examples.
Personally I add Mockito / PowerMock to the mix for mocking internal dependencies away.
Good luck.

It depends on what kind of test you want to implement.
Certainly Spring Test helps in this. This module supports "unit" and integration testing. Note that unit tests are not really true unit tests because there is a little bit of context loading involved while using Spring Test at it's minimum.
Check the MockMvc class that you can use to make requests to controllers.

I think the best way is to use ContextConfiguration in combination with DirtiesContext, MockMvcBuilders and Mockito. This gives you the advantage of creating a Spring controller through an application context and injecting beans whose behaviour is defined through Mockito. In this case you can reach high line and condition coverage. Here is an example for your code:
#ContextConfiguration
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
#RunWith(SpringJUnit4ClassRunner.class)
public class FooControllerTest {
private MockMvc mockMvc;
#Autowired
private FooService service;
#Autowired
private FooController controller;
#Before
public void initController() {
mockMvc = MockMvcBuilders.standaloneSetup(frontEndController).build();
}
#Test
public void shouldDoSomeThing_CornerCase() {
// Given:
// define the behaviour of service with when(service...)
// Then:
// perform a request on contoller
mockMvc.perform(get("/foo/delete/{id}"))
// When:
// user Mockito verify
// or
// MockMvcRequestBuilders
}
#Configuration
public static class FooConfiguration {
#Bean
public FooController controller() {
return new FooController();
}
#Bean
public FooService service() {
return mock(FooService.class);
}
}
}
DirtiesContext is important so that you get clean mocks a every test.

Finally I use this solution.
For my Domain Model I use this link http://www.javacodegeeks.com/2014/09/tips-for-unit-testing-javabeans.html
/**
* #param <T>
*/
public abstract class AbstractJavaBeanTest<T> {
protected String[] propertiesToBeIgnored;
protected abstract T getBeanInstance();
#Test
public void beanIsSerializable() throws Exception {
final T myBean = getBeanInstance();
final byte[] serializedMyBean = SerializationUtils.serialize((Serializable) myBean);
#SuppressWarnings("unchecked")
final T deserializedMyBean = (T) SerializationUtils.deserialize(serializedMyBean);
assertEquals(myBean, deserializedMyBean);
}
#Test
public void equalsAndHashCodeContract() {
EqualsVerifier.forClass(getBeanInstance().getClass()).suppress(Warning.STRICT_INHERITANCE, Warning.NONFINAL_FIELDS).verify();
}
#Test
public void getterAndSetterCorrectness() throws Exception {
final BeanTester beanTester = new BeanTester();
beanTester.getFactoryCollection().addFactory(LocalDateTime.class, new LocalDateTimeFactory());
beanTester.testBean(getBeanInstance().getClass());
}
class LocalDateTimeFactory implements Factory {
#Override
public LocalDateTime create() {
return LocalDateTime.now();
}
}
}
/**
* Test Foo
*/
public class FooTest extends AbstractJavaBeanTest<Foo> {
#Override
protected Foo getBeanInstance() {
return new Foo();
}
}
I add this dependencies to pom.xml:
<dependency>
<groupId>nl.jqno.equalsverifier</groupId>
<artifactId>equalsverifier</artifactId>
<version>1.7.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.meanbean</groupId>
<artifactId>meanbean</artifactId>
<version>2.0.3</version>
</dependency>
For my MVC controllers I use this link http://www.luckyryan.com/2013/08/24/unit-test-controllers-spring-mvc-test/
/**
* Test FooController
*/
public class FooControllerTest {
#Mock
private FooService fooService;
#InjectMocks
private FooController fooController;
private MockMvc mockMvc;
#Before
public void setup() {
// Process mock annotations
MockitoAnnotations.initMocks(this);
// Setup Spring test in standalone mode
this.mockMvc = MockMvcBuilders.standaloneSetup(fooController).build();
}
#Test
public void testAdd() throws Exception {
Foo foo = new Foo();
// given
given(FooService.createFoo()).willReturn(foo);
// when
// then
this.mockMvc.perform(get("/foo/new"))
.andExpect(forwardedUrl("foo/detail"))
.andExpect(model().attributeExists("foo"))
.andExpect(model().attribute("foo", is(foo)));
}
#Test
public void testDetail() throws Exception {
Foo foo = new Foo();
Long fooId = 1L;
// given
given(fooService.findById(fooId)).willReturn(foo);
// when
// then
this.mockMvc.perform(get("/foo/" + fooId))
.andExpect(forwardedUrl("foo/detail"))
.andExpect(view().name("foo/detail"))
.andExpect(model().attributeExists("foo"))
.andExpect(model().attribute("foo", is(foo)));
}
#Test
public void testSave() throws Exception {
Foo foo = new Foo();
// given
// when
// then
//With form errors
this.mockMvc.perform(post("/foo/update")
.param("name", "")
.sessionAttr("foo", foo))
.andExpect(forwardedUrl("foo/detail"))
.andExpect(model().hasErrors())
.andExpect(model().attributeHasFieldErrors("foo", "name"));
//Without form errores
this.mockMvc.perform(post("/foo/update")
.param("name", "nameValue")
.param("code", "codeValue")
.param("date", "20/10/2015")
.requestAttr("referer", "/foo/list")
.sessionAttr("foo", foo))
.andExpect(view().name("redirect:" + "/foo/list"))
.andExpect(model().hasNoErrors())
.andExpect(flash().attributeExists("message"))
.andExpect(flash().attribute("message", hasProperty("message", is("message.ok"))))
.andExpect(flash().attribute("message", hasProperty("type", is(Message.Type.SUCCESS))))
.andExpect(status().isFound());
}
#Test
public void testDelete() throws Exception {
Foo foo = new Foo();
foo.setOtherFoos(new ArrayList<OtherFoo>());
Long fooId = 1L;
// given
given(fooService.findByIdWithOtherFoos(fooId)).willReturn(foo);
// when
// then
//Without errors: without other foos
this.mockMvc.perform(post("/foo/delete/" + fooId)
.sessionAttr("foo", foo)
.requestAttr("referer", "/foo/list"))
.andExpect(view().name("redirect:" + "/foo/list"))
.andExpect(flash().attributeExists("message"))
.andExpect(flash().attribute("message", hasProperty("message", is("message.ok"))))
.andExpect(flash().attribute("message", hasProperty("type", is(Message.Type.SUCCESS))));
// given
foo.getOtherFoos().add(new OtherFoo());
given(fooService.findByIdWithOtherFoos(fooId)).willReturn(foo);
// when
// then
//With errors: with other foos
this.mockMvc.perform(post("/foo/delete/" + fooId)
.sessionAttr("foo", foo)
.requestAttr("referer", "/foo/list"))
.andExpect(view().name("redirect:" + "/foo/list"))
.andExpect(flash().attributeExists("message"))
.andExpect(flash().attribute("message", hasProperty("message", is("message.error"))))
.andExpect(flash().attribute("message", hasProperty("type", is(Message.Type.DANGER))));
}
}
For my JUnit service test I implemented a class for Configuration and I load it in the service test
#Configuration
public class FooServiceImplTestConfiguration {
#Bean
public FooService fooService() {
return new FooServiceImpl();
}
#Bean
public FooRepository fooRepository() {
return Mockito.mock(FooRepository.class);
}
}
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {FooServiceImplTestConfiguration.class})
public class FooServiceImplTest {
#Inject
private FooRepository fooRepository;;
#Inject
private FooService fooService;
#BeforeClass
public static void oneTimeSetUp() {
// one-time initialization code
System.out.println("#BeforeClass - oneTimeSetUp");
}
#AfterClass
public static void oneTimeTearDown() {
// one-time cleanup code
System.out.println("#AfterClass - oneTimeTearDown");
}
#Before
public void setUp() {
}
#After
public void tearDown() {
}
#Test
public void createFoo() {
assertNotNull(fooService.createFoo());
}
#Test
public void save() {
//New foo
Foo saveFoo = new Foo();
// given
// when
fooService.save(saveFoo);
// then
assertNotNull(saveFoo.getDate());
saveFoo.setId(1L);
Date date = new Date();
saveFoo.setDate(date);
// given
//when
fooService.save(saveFoo);
//then
assertThat(date, is(saveFoo.getDate()));
}
#Test
public void delete() {
//given
//when
fooService.deleteFoo(Matchers.anyLong());
//then
}
#Test
public void findById() {
Long id = 1L;
Foo fooResult = new Foo();
//given
given(fooRepository.findOne(id)).willReturn(fooResult);
//when
Foo foo = fooService.findById(id);
//then
assertThat(foo, is(fooResult));
}
#Test
public void findByIdWithOtherFoos() {
Long id = 1L;
Foo fooResult = new Foo();
//given
given(fooRepository.findOne(id)).willReturn(fooResult);
//when
Foo foo = fooService.findByIdWithOtherFoos(id);
//then
assertThat(foo, is(fooResult));
}
#Test
public void findAll() {
Page<Foo> fooResult = new PageImpl<>(new ArrayList<Foo>());
given(fooRepository.findAll(Matchers.<Pageable>anyObject())).willReturn(fooResult);
//when
Page<Foo> foos = fooService.findAll(Matchers.<Pageable>anyObject());
//then
assertThat(foos, is(fooResult));
}
#Test
public void findAllList() {
List<Foo> fooResult = new ArrayList<Foo>();
given(fooRepository.findAll(Matchers.<Sort>anyObject())).willReturn(fooResult);
//when
List<Foo> foos = fooService.findAll(Matchers.<Sort>anyObject());
//then
assertThat(foos, is(fooResult));
}
}
In my pom I need add this dependencies:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.2.3.RELEASE</version>
</dependency>
<!-- This is for mocking the service -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
<!-- Optional -->
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
I need change the my hibernate validator version for this:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.1.3.Final</version>
</dependency>
I need add this dependencies too because I got this excecption:
Cause: java.lang.AbstractMethodError:org.hibernate.validator.internal.engine.ConfigurationImpl.getDefaultParameterNameProvider()Ljavax/validation/ParameterNameProvider;
Detail message: org.hibernate.validator.internal.engine.ConfigurationImpl.getDefaultParameterNameProvider()Ljavax/validation/ParameterNameProvider;
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>el-impl</artifactId>
<version>2.2</version>
</dependency>
I'm using spring data, I need to do the test for my custom CrudRepositories too.

Related

#MockBean service field is always null in a Test class with #WebMvcTest

I'm trying to improve a unit test for a service I'm developing. I read somewhere that it's ideal to use #WebMvcTest annotation over #SpringBootTest when testing the Web or Controller layer.
However, for some reason, a #MockBean service field I am using in the Test class is always NULL.
java.lang.AssertionError: Expecting actual not to be null
In the test class below, serviceIsLoaded() method is always null when I run that single test.
SectionRESTControllerTest.java
#WebMvcTest
public class SectionRESTControllerTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private SectionServiceImpl sectionServiceImpl;
#Test
public void serviceIsLoaded() {
assertThat(sectionServiceImpl).isNotNull();
}
}
SectionServiceImpl.java
#Service
public class SectionServiceImpl implements SectionService {
private final Logger logger = LoggerFactory.getLogger(SectionServiceImpl.class);
#Autowired
private SectionRepository sectionRepo; //saves to section table
#Autowired
private GradeLevelRepository gradeLevelRepo;
#Override
public Section createSection(Section section) {...}
#Override
public Section updateSection(Section request) throws Exception {...}
#Override
public Section getSectionById(Long id) {
return sectionRepo.findById(id).get();
}
#Override
public List<Section> getAllActiveSections() {
return sectionRepo.findSectionByIsActiveTrue();
}
#Override
public List<Section> getAllInActiveSections() {
return sectionRepo.findSectionByIsActiveFalse();
}
#Override
public List<Section> getSectionsByGradeLevelId(Long id) {
return sectionRepo.findByGradeLevelId(id);
}
#Override
public List<Section> getSectionByGradeLevelCode(String code) {
return sectionRepo.findByGradeLevelCode(code);
}
#Override
public List<Section> getSectionByGradeLevelCategory(String category) {
return sectionRepo.findByGradeLevelCategory(category);
}
}
My understanding is, with #WebMvcTest, it does not load the entire application context with all managed beans which makes the UnitTest run faster. Unlike, #SpringBootTest which loads everything when running the UnitTest.
SectionService.java
public interface SectionService {
Section createSection(Section section);
Section updateSection(Section section) throws Exception;
Section getSectionById(Long id);
List<Section> getAllActiveSections();
List<Section> getAllInActiveSections();
List<Section> getSectionsByGradeLevelId(Long id);
List<Section> getSectionByGradeLevelCode(String code);
List<Section> getSectionByGradeLevelCategory(String category);
}
Main class
#SpringBootApplication
public class AutoformSettingsServiceApplication {
public static void main(String[] args) {
SpringApplication.run(AutoformSettingsServiceApplication.class, args);
}
}
Do you have any thoughts or ideas why the #MockBean sectionServiceImpl is null
Thank you.

How can I test a validator in a Spring Boot app?

I have a class:
#Component
public class ContractorFormValidator implements Validator {
Logger logger = LoggerFactory.getLogger(ContractorFormValidator.class);
#Inject IBusinessDataValidator businessDataValidator;
#Override
public boolean supports(Class<?> clazz) {
return Contractor.class.equals(clazz);
}
#Override
public void validate(Object target, Errors errors) {
Contractor contractor = (Contractor) target;
if (!businessDataValidator.isNipValid(contractor.getContractorData().getNip())) {
errors.rejectValue("contractorData.nip", "invalid");
}
if (!businessDataValidator.isRegonValid(contractor.getContractorData().getRegon())) {
errors.rejectValue("contractorData.regon", "invalid");
}
}
}
How can I test it? I have tried this: How to test validation annotations of a class using JUnit? but this doesn't work cause the validate method in my validator requires Errors class passed to it's method signature.
I have no Idea if I can pass this Errors object to the validator. Is there any other way?
Have you tried to write a simple unit test for this?
#RunWith(SpringJUnit4ClassRunner.class)
public class ContractorFormValidatorTest {
#Autowired
private ContractorFormValidator validator;
#Test
public void testValidation() throws Exception {
Contractor contractor = new Contractor();
// Initialise the variables here.
Errors errors = new BeanPropertyBindingResult(contractor, "contractor");
validator.validate(contract, errors);
// If errors are expected.
Assert.assertTrue(errors.hasErrors());
for (Error fieldError : errors.getFieldErrors()) {
Assert.assertEquals("contractorData.nip", fieldError.getCode());
}
}
}
If you are going to use the validator in a controller implementation, then you need to use the MockMvc apis
Your set up can be included in the class above.
private MockMvc mockMvc
#Autowired
private MyController controller;
#Before
public void setUp() throws Exception {
this.mockMvc = MockMvcBuilders.standaloneSetup(this.controller).build();
}
#Test
public void testMethod() {
MvcResult result = this.mockMvc.perform(MockMvcRequestBuilders.post("/yoururl")).
andExpect(MockMvcResultMatchers.status().isCreated()).andReturn();
}
Use the class org.springframework.validation.BeanPropertyBindingResult,
Errors newErrors = new BeanPropertyBindingResult(validateObject, "objectName");

Using Mockito 'when' in controller testing

I'm trying to test my controller method in Play framework 2.4.6.
Inside my controller method, I have the following code:
User user = accountService.getUserByEmail(email);
if (user == null) {
//Path A
}
//Path B
When running the test, user will be null. Hence I can't test Path B. I tried returning a User using Mockito when, but it didn't work either. Is there any other way of doing it?
Below is my test code:
RequestBuilder request = new RequestBuilder()
.method("POST")
.bodyForm(ImmutableMap.of("email", "test#test.com"))
.uri(controllers.routes.ResetPasswordController.postResetPassword().url());
when(accountService.getUserByEmail(anyString())).thenReturn(new User());
assertEquals(OK, route(request).status());
Thanks to #Andriy for pointing me in the right direction for Dependency Injection.
I managed to solved the issue with the following setup.
Test:
public class TestClass {
#Inject
Application application;
final AccountService accountServiceMock = mock(AccountService.class);
#Before
public void setup() {
Module testModule = new AbstractModule() {
#Override
public void configure() {
bind(AccountService.class).toInstance(accountServiceMock);
}
};
GuiceApplicationBuilder builder = new GuiceApplicationLoader()
.builder(new ApplicationLoader.Context(Environment.simple()))
.overrides(testModule);
Guice.createInjector(builder.applicationModule()).injectMembers(this);
Helpers.start(application);
}
#Test
public void testMethod() throws Exception {
RequestBuilder request = new RequestBuilder()
.session("userId", "1")
.uri(controllers.routes.AccountController.addAccount().url());
running(application, () -> {
when(accountServiceMock.addAccount().thenReturn(true);
assertEquals(OK, route(request).status());
});
}
Controller:
#Singleton
public class AccountController extends Controller {
private AccountService accountService;
#Inject
public Controller(AccountService a) {
accountService = a;
}
public Result addAccount() {
boolean success = accountService.addAccount();
}
}
Interface:
#ImplementedBy(AccountServiceImpl.class)
public interface AccountService {
boolean addAccount();
}
Implementation:
public class AccountServiceImpl implements AccountService {
#Override
public boolean addAccount() {
}
}
My knowledge is minimal on the concepts going on here, but roughly:
Controller is stateless just like HTML, hence you need runtime dependency injection to get Play to recognise the mock object.
Useful documentations:
https://www.playframework.com/documentation/2.4.x/JavaTestingWithGuice
https://www.playframework.com/documentation/2.4.x/JavaDependencyInjection

Using autowired dependencies with certain mock dependency in Spring4

I have a rest resource for signup and login. both in a controller class. the controller class has a dependency to a service class with the business logic. the service class has further dependencies. cause i use an embedded db for testing, i want to use the real dependencies of my app instead to mock them with something like #injectmock #mock. there is only one certain dependency i have to mock. its the dependency for sending emails after a signup process. how to write test cases with #autowired function and one certain mock dependency for email notification?
#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());
}
}
I hope you see the problem. Every dependency works fine instead mailservice. I dont want to use #injectmock and #mock with MockitoAnnotations.initMocks(this); in my test file, because of the neccessary to provide for all dependencies mocks.
if your dependencies are running and you have a configuration class where you have defined the endpoint, you can use ConfigurableApplicationContext class, something like this:
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);
}
}
Or you can re-write your endpoint with a configuration class and you can use WireMock (http://wiremock.org) to emulate your dependency with real data, this should be something like this:
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);
}});
}};
}
}
}
I hope this help you.
What you are trying to do is easily implemented using Spring Profiles.
On way to achieve it is the following:
#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);
}
}
Your test class would then look like:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = TestConfiguration.class)
#Transactional
#TransactionConfiguration(defaultRollback = true)
#ActiveProfiles("mockMail")
public class LogoutTest {
//do your testing
}
Note the use of #Primary in MockMailServiceConfig. I opted for this way since it wouldn't require you to introduce profiles anywhere else if you are not already using them. #Primary tells spring to use that specific bean if multiple candidates are available (in this case there is the real mail service and the mock service)

Spring Transactional Parameterized Test and Autowiring

Is there a way to get a class that extends AbstractTransactionalJUnit4SpringContexts to play nicely with JUnit's own #RunWith(Parameterized.class), so that fields marked as Autowired get wired in properly?
#RunWith(Parameterized.class)
public class Foo extends AbstractTransactionalJUnit4SpringContextTests {
#Autowired private Bar bar
#Parameters public static Collection<Object[]> data() {
// return parameters, following pattern in
// http://junit.org/apidocs/org/junit/runners/Parameterized.html
}
#Test public void someTest(){
bar.baz() //NullPointerException
}
}
See http://jira.springframework.org/browse/SPR-5292
There is a solution.
You can use a TestContextManager from Spring. In this example, I'm using Theories instead of Parameterized.
#RunWith(Theories.class)
#ContextConfiguration(locations = "classpath:/spring-context.xml")
public class SeleniumCase {
#DataPoints
public static WebDriver[] drivers() {
return new WebDriver[] { firefoxDriver, internetExplorerDriver };
}
private TestContextManager testContextManager;
#Autowired
SomethingDao dao;
private static FirefoxDriver firefoxDriver = new FirefoxDriver();
private static InternetExplorerDriver internetExplorerDriver = new InternetExplorerDriver();
#AfterClass
public static void tearDown() {
firefoxDriver.close();
internetExplorerDriver.close();
}
#Before
public void setUpStringContext() throws Exception {
testContextManager = new TestContextManager(getClass());
testContextManager.prepareTestInstance(this);
}
#Theory
public void testWork(WebDriver driver) {
assertNotNull(driver);
assertNotNull(dao);
}
}
I found this solution here : How to do Parameterized/Theories tests with Spring
You can use SpringClassRule and SpringMethodRule for this purpose
#RunWith(Parameterized.class)
#ContextConfiguration(...)
public class FooTest {
#ClassRule
public static final SpringClassRule SPRING_CLASS_RULE = new SpringClassRule();
#Rule
public final SpringMethodRule springMethodRule = new SpringMethodRule();
#Autowired
private Bar bar
#Parameters
public static Collection<Object[]> data() {
// return parameters, following pattern in
// http://junit.org/apidocs/org/junit/runners/Parameterized.html
}
#Test
public void someTest() {
bar.baz() //NullPointerException
}
}
No, you can't. The superclass has:
#RunWith(SpringJUnit4ClassRunner.class)
which assures that the tests are run within spring context. If you replace it, you are losing this.
What comes to my mind as an alternative is to extend SpringJunit4ClassRunner, provide your custom functionality there and use it with #RunWith(..). Thus you will have the spring context + your additional functionality. It will call super.createTest(..) and then perform additional stuff on the test.
I've had to handle the transactions programmatically (see http://www.javathinking.com/2011/09/junit-parameterized-test-with-spring-autowiring-and-transactions/):
#RunWith(Parameterized.class)
#ContextConfiguration(locations = "classpath*:/testContext.xml")
public class MyTest {
#Autowired
PlatformTransactionManager transactionManager;
private TestContextManager testContextManager;
public MyTest (... parameters for test) {
// store parameters in instance variables
}
#Before
public void setUpSpringContext() throws Exception {
testContextManager = new TestContextManager(getClass());
testContextManager.prepareTestInstance(this);
}
#Parameterized.Parameters
public static Collection<Object[]> generateData() throws Exception {
ArrayList list = new ArrayList();
// add data for each test here
return list;
}
#Test
public void validDataShouldLoadFully() throws Exception {
new TransactionTemplate(transactionManager).execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
status.setRollbackOnly();
try {
... do cool stuff here
} catch (Exception e) {
throw new RuntimeException(e);
}
return null;
}
});
}
Here's how I made it work in Spring Boot 1.5.7:
Add the #RunWith(Parameterized.class) annotation to your class
Inject your dependency as class field with:
#Autowired
private Bar bar;
Add your parameter/s as class fields:
private final int qux;
private final Boolean corge;
private final String grault;
Add a constructor to initialize the parameter/s as follows:
public Foo(int qux, Boolean corge, String grault) throws Exception {
this.qux = qux;
this.corge = corge;
this.grault = grault;
new TestContextManager(getClass()).prepareTestInstance(this);
}
Add a static method data that returns a Collection containing the values of your parameters at each iteration, respecting the order by which they are passed to the constructor:
#Parameterized.Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][]{
{ 1, Boolean.FALSE, "Hello" },
{ 2, Boolean.TRUE, null },
{ 3, null, "world" }
});
}
Write your test using the class fields declared above like follows:
#Test public void someTest(){
// Some arrangements
// Some actions
assertThat(myTestedIntValue, is(equalTo(qux));
assertThat(myTestedBooleanValue, is(equalTo(corge));
assertThat(myTestedStringValue, is(equalTo(grault));
}
Inspired by Simon's solution, you can use TestContextManager also with Parameterized runner:
#RunWith(Parameterized.class)
#ContextConfiguration(locations = "classpath:/spring-context.xml")
public class MyTestClass {
#Parameters public static Collection data() {
// return parameters, following pattern in
// http://junit.org/apidocs/org/junit/runners/Parameterized.html
}
#Before
public void setUp() throws Exception {
new TestContextManager(getClass()).prepareTestInstance(this);
}
}
Here is full example
I am not sure about handling #Transactional in this case.

Categories

Resources