[INFO] Reactor Summary:
[INFO]
[INFO] ix-checkit-dc ..................................... SUCCESS [0.003s]
[INFO] ix-checkit-contract ............................... SUCCESS [1.642s]
[INFO] ix-checkit-frontend: jquery, spring mvc ........... SUCCESS [2.345s]
[INFO] ix-checkit-backend: spring data rest, psql/h2 ..... SUCCESS [6.165s]
[INFO] ix-checkit-test: selenium IT ...................... SUCCESS [19.118s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
Multi war Integration Test with selenium, mockMvc, jetty, h2 as TDD guard test project
Monday, August 15, 2016
The road to hell is paved with good intentions
Motivation
- During TDD there is a risk to break contracts between different components represented with war files
- It is useful to add a separate test project to run lightweight multi war integration tests to check the whole application integrity. These tests should be executed during common checkin build process as a part of continuous integration
Example application includes
- Backend war project, implemented with spring data rest. It has its own TDD tests implemented with mockMvc. There is no need in container, just mockMvc, to test the rest-services representing db entities. Test db is H2
- Front-end war project, implemented with spring MVC, and jquery. It has its own TDD tests implemented with Mockito.
- Selenium test project. Integration tests use jetty to deploy front-end and to test jsp pages. There is only one instance of jetty is used to deploy front-end. Backend mockMvc is used to test backend and to provide data for front-end. MockMvc instance is created in the context of the test itself and then it is passed to front-end, deployed in jetty context, through the dedicated static field of the front-end test (fake) service. So the Selenium test project is lightweight and can be run during the build process.
- Spring annotation configuration.
Test example
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { BEAppConfigurationDev.class,
BEWebConfigurationDev.class })
@ActiveProfiles("dev")
@Transactional
@WebAppConfiguration
public class CheckItSeleniumIT {
protected MockMvc backEndMockMvc;
@Autowired
private WebApplicationContext backEndWebApplicationContext;
@Autowired
private ItemService itemService;
@Before
public void setUp() throws Exception, BEError {
prepareSeleniumDriver(); check next pic. for details
createBackEndMockMvcAndPassItToJettyContext();
prepareAndStartJetty();
}
@Test
public void testCheckItGoToEditPage() throws Exception {
load_checkIt_homePage();
when_double_click_on_first_row_of_itemGrid_Then_go_to_edit_page();
when_an_option_entered_Then_it_is_in_the_option_grid();
}
private void load_checkIt_homePage() {
seleniumDriver.get(seleniumBaseUrl + "/items");
}
private voidwhen_double_click_on_first_row_of_itemGrid_Then_go_to_edit_page() {
WebElement row = (new WebDriverWait(seleniumDriver, 10))
.until(ExpectedConditions.presenceOfElementLocated(
By.cssSelector("table[id='list'] tr[id='1']")));
Actions builder = new Actions(seleniumDriver);
Action doubleClick = builder.moveToElement(row).doubleClick().build();
doubleClick.perform();
}
private voidwhen_an_option_entered_Then_it_is_in_the_option_grid() {
seleniumDriver.findElement(By.id("itemTextInput222")).clear();
seleniumDriver.findElement(By.id("itemTextInput222"))
.sendKeys("aaabbbccc");
seleniumDriver.findElement(By.name("itemOption.itemComments"))
.clear();
seleniumDriver.findElement(By.name("itemOption.itemComments"))
.sendKeys("dddeeefff");
seleniumDriver.findElement(By.cssSelector(
"#addOption > div.btBox > button[type=\"submit\"]")).click();
seleniumDriver.findElement(By.cssSelector("span[title=\"dddeeefff\"]"))
.click();
WebElement itemText = (new WebDriverWait(seleniumDriver, 10))
.until(ExpectedConditions.presenceOfElementLocated(
By.cssSelector("span[title=\"dddeeefff\"]")));
assertEquals("aaabbbccc",itemText.getText());
}
setUp details
private void prepareSeleniumDriver() {
seleniumDriver = new ChromeDriver();
}
private void createBackEndMockMvcAndPassItToJettyContext() {
backEndMockMvc = webAppContextSetup(backEndWebApplicationContext).build();
itemService.setMockMvc(backEndMockMvc);
}
private void prepareAndStartJetty() throws Exception {
createJetty();
initJettyServerConnector();
createJettyContextAndStart();
}
private void createJetty() {
jetty = new Server(8080);
jetty.setStopAtShutdown(true);
}
private void initJettyServerConnector() {
ServerConnector scc = new ServerConnector(jetty);
scc.setPort(8080);
jetty.setConnectors(new Connector[] { scc });
}
private void createJettyContextAndStart() throws Exception {
WebAppContext context = createAndConfigureJettyContext();
jetty.setHandler(context);
jetty.start();
}
private WebAppContext createAndConfigureJettyContext() {
WebAppContext context = createJettyContext();
configureJettyContextWithFrontEndInitializer(context);
return context;
}
private WebAppContext createJettyContext() {
WebAppContext context = new WebAppContext();
context.setServer(jetty);
context.setResourceBase("target/war/work/ru.ix.item.ui/ix-checkit-frontend");
context.setContextPath("/ix-checkit-frontend");
return context;
}
private voidconfigureJettyContextWithFrontEndInitializer(WebAppContext context) {
context.setConfigurations(new Configuration[]{
new WebXmlConfiguration(),
new AnnotationConfiguration() {
@Override
public void preConfigure(WebAppContext context) throws Exception {
final ClassInheritanceMap map = new ClassInheritanceMap();
final ConcurrentHashSet set = new ConcurrentHashSet<>();
set.add(FEWebAppInitializerDev.class.getName());
map.put(WebApplicationInitializer.class.getName(), set);
context.setAttribute(CLASS_INHERITANCE_MAP, map);
_classInheritanceHandler = new ClassInheritanceHandler(map);
}
}
});
}
Summary
Once upon a time I participated in some interesting project. There was a lot of war based components. There was a dedicated testing team. There was a lot of tests, all war component interactions had test-automation stuff, but
one external link with CRM component. This link, as it was found after tdd had been completed, was the most important.
Subscribe to:
Posts (Atom)