Skip to content

Instantly share code, notes, and snippets.

@thekalinga
Last active August 29, 2015 14:23
Show Gist options
  • Save thekalinga/c55b652cc9cd6831608e to your computer and use it in GitHub Desktop.
Save thekalinga/c55b652cc9cd6831608e to your computer and use it in GitHub Desktop.
Blind vision for integration testing
@RunWith(JUnit4.class)
// Mockito + Spring integration/ use native @InjectMocks of mockito
@EnableMockedBean
// Spring MVC test configuration
@ContextConfiguration
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class,
// DBUnit & Spring integration
DbUnitTestExecutionListener.class })
// PowerMock
@PrepareForTest( { CustomUtil.class })
class GuineaPigResourceTests {
// Assumption is that all these would hook into the lifecycle in the order in which these are specified
// All these rules might needs to be collated in some form
// Does not exist yet as for as I know
@Rule
NestedRunner nestedRunner = new NestedRunner();
// Spring rules, exist in > 4.2
@ClassRule
static SpringClassRule SPRING_CLASS_RULE = new SpringClassRule();
@Rule
SpringMethodRule springMethodRule = new SpringMethodRule();
// Does not exist yet as for as I know
@Rule
JunitParamsRunner junitParamsRunner = new JunitParamsRunner();
// Does not exist yet as for as I know
@Rule
AssumesRunner assumesRunner = new AssumesRunner();
// Exists in the latest beta of Mockito
@Rule
MockitoRule rule = MockitoJUnit.rule();
// Already present
@Rule
PowerMockRule rule = new PowerMockRule();
// Global vars
// This mocked bean is already injected into GuineaPigService by the therore-spring-mockito library, whcih you can use to set expectations
@MockedBean
private EmailService emailService;
@Resource
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
@Before
void setUp() {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
public class AddNewGuineaPig {
@Before
public void setup() {}
@Test
@Params(method = "validGuineaPigsProvider")
void withValidValues_ShouldSave(GuineaPig guineaPig) {
// we can even capture this argument using arguments captor and verify at the end
when(emailService.send(anyObject()));
when(CustomUtil.validateImage(ayString())).thenReturn(true); // power mockito
mockMvc.perform(
post("/")
.content(guineaPig)
.accepts(MediaType.APPLICATION_JSON)..
)
.andExpect(status().isOk())
.andExpect(jsonPath("$.id", is(notNull())))
.andExpect(jsonPath("$.name", is(guineaPig.getName())));
// we may want to do a get on the new id and verify
// Mockito verify
verify(emailService.times(1));
verify(validateImage()).times(1);
}
@Test
// This test only makes sense after the save is successful, if its not succeeding lets skip this test altogeather
@Assumes(method = "withValidValues_ShouldSave")
void afterSave_EmailMessageHasCorrectSender() {
// do additional cerifications
}
@Test
@Params(method = "invalidGuineaPigsProvider")
void withInvalidData_ShouldReturnUnProcessableEntity(GuineaPig guineaPig) {
mockMvc.perform(
post("/")
.content(guineaPig)
.accepts(MediaType.APPLICATION_JSON)
)
.andExpect(status().is422());
// Mockito verify that email is not sent
verify(emailService.none());
}
@Test
// DBUnit to populate some existing guinnea pigs
@DatabaseSetup("GuineaPigs.xml")
void withNonUniqueProperty_ShouldReturnUnProcessableEntity() {
GuineaPig guineaPigWithDuplicateLicenseNumber = new GuineaPig.Builder()....build();
mockMvc.perform(
post("/")
.content(guineaPigWithDuplicateLicenseNumber)
.accepts(MediaType.APPLICATION_JSON)
)
.andExpect(status().is422());
// Mockito verify that email is not sent
verify(emailService.none());
}
private GuineaPig[] validGuineaPigsProvider() {
// or read from the file
return new GuineaPig[] {
new GuineaPig.Builder().name("Name").breed("Breed").description("Desc").build(),
new GuineaPig.Builder().name("SomeOtherName").breed("Breed").description("Desc").build()
};
}
private GuineaPig[] invalidGuineaPigsProvider() {
// or read from the file
return new GuineaPig[] {
new GuineaPig.Builder().name("").breed("Breed").description("Desc").build(),
new GuineaPig.Builder().name("Toooooooooooooooooooo Longggggggggg").breed("Breed").description("Desc").build()
};
}
}
}
@RestController
@RequestMapping(consumes=MediaType.APPLICATION_JSON_VALUE, produces=MediaType.APPLICATION_JSON_VALUE)
class GuineaPigResource {
@Autowired
GuineaPigService guineaPigService;
@RequestMapping(method=POST)
GuineaPig save(GuineaPig pig) {
return guineaPigService.save(pig);
}
}
interface GuineaPigService {
GuineaPig save(GuineaPig pig);
}
class GuineaPigServiceImpl implements GuineaPigService {
@Autowired
EmailService emailService;
GuineaPig save(GuineaPig pig) {
// Save using DAO
// Storing the image in db is clearly a bad idea, this is here to illustrate the example
CustomUtil.validateImage(pig.imageAsBase64);
// construct emailMessage
emailService.send(emailMessage);
}
}
interface EmailService {
void send(Message message);
}
class SendMailEmailService implements EmailService {
void send(Message message) {
// send using SendMail service
}
}
@Builder
@AllArgsConstructor
class GuineaPig {
// name validation rules
// 1. name length must be between 2-10 chars
// 2. name must be alphabets only
// 3. other rules
String name;
String uniquePropery;
String breed;
String image;
String description; // optional
}
class CustomUtil {
private CustomUtil() {}
static void validateImage() {
// has constaints like running in a specific env/takes a long time to compute
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment