The Dawn of ZK Application Test Suite:Mimic Library"

From Documentation
Line 45: Line 45:
  
 
== Setup ==
 
== Setup ==
Before writing test cases with mimic library, you have to include '''zats-mimic.jar''' and '''jetty.jar''' to your project.
+
To writing test cases with mimic library, you have to include '''zats-mimic.jar''' and '''jetty.jar''' to your project.
  
 
== Write a Test Case ==
 
== Write a Test Case ==

Revision as of 00:33, 27 March 2012

WarningTriangle-32x32.png This page is under construction, so we cannot guarantee the accuracy of the content!


DocumentationSmall Talks2012AprilThe Dawn of ZK Application Test Suite:Mimic Library
The Dawn of ZK Application Test Suite:Mimic Library

Author
Hawk Chen, Engineer, Potix Corporation
Date
Version
0.9.0 Freshly

Opening

In agile software development, developers modify their codes frequently for requirement change or refactoring, so they also perform unit test frequently to ensure the software quality. In ZK-based application, the composer which is tightly-couple with ZUL is hard to be unit tested because it is instantiated when a ZUL is requested by a browser. Hence TDD (Test-Driven Development) cannot work under this situation. Agile developer may deploy the web application to a server and test it with the browser. But writing automation test to control a browser is an issue, and testing for different browsers is also a trouble. Not to mention that running a unit test in an application server is time-consuming and could be agile developer's darkest time. Don't be depressed, let me light your path with twilight of ZK Test Suite - Mimic Library.

Mimic Library : No Server Test

Mimic library enables tester to test their composer without application server, of course without browser, either. Through this library, tester can mimic user interactions to applications such as clicking or typing to verify composer's (controller layer) data and logic. All they have to do is to write a regular unit test case with JUnit and use mimic library's utility class to interact components on ZUL. Then run the test case, it will load your project's ZUL with a server emulator. But no screen is rendered, it just simulates user interaction to the server. Tester can verify result by checking component's property or model.

No deploying to server, no rendering on browser, the unit test case can be executed in very short time. This is very helpful to frequently unit testing during agile development process.

The concept is as follows:

Smalltalk-MimicLibraryConcept.png

Tester writes test case to manipulate mimic component with mimic operation which simulates user action like clicking or typing. These operations will be sent to server emulator and related event handlers written in a composer will be invoked to change component's status. Tester can check component's properties to verify the result of user action. It might be a label change its value or a Listbox increases one item. Those behaviors that reflect on component's properties can be verified.

Limitation

As this library focuses on testing composer's logic on the server side, there are some limitation you should know:

  • Functions that depend on the application server cannot work.
    Test cases are run in simulated environment, all functions that requires an application server cannot work properly (e.g. JNDI, or JTA). If user's AUT (Application Under Test) project adopts such container-provided services, they need extra work to make it work normally out of a container, e.g. use Test Double like fake object.
  • Cannot test browser’s behavior.
    In ZK-based application, some behaviors are handled by browser(JavaScript), e.g. popup menu. As server side is not aware of these behaviors, we cannot verify it.
  • Cannot test visual effects.
    It cannot verify any behavior that doesn't reflect on component's properties like animations, or a component's visual effect.

Hello Mimic Test

To present basic usage of mimic library, we demonstrate how to test a simple application. The application has only 1 button and 1 label, after clicking it, the label will show "Hello Mimic".


Smalltalk-MimicLibrary-hello.png


Setup

To writing test cases with mimic library, you have to include zats-mimic.jar and jetty.jar to your project.

Write a Test Case

The steps to write test case are:

  1. Setup web application content path
  2. Open a conversation with a ZUL
  3. Find a component
  4. Perform an operation on a component
  5. Verify result by checking a component’s property
  6. Tear down, stop server emulator


Before looking into test case's source code, let me introduce some basic classes used in test case.

Conversation
It represents a client to the server emulator and also maintains connection state.
Conversations
(Notice the ended 's' ) It contains several utility methods to control Conversation .
ComponentAgent
To mimic a ZK component, determine which operation you can perform on it. We can also get ZK component property's value from it.
OperationAgent (ClickAgent, TypeAgent, SelectAgent...)
To mimic available user operation to a ZK component.
We name it with word "Agent" because it's not the user operation itself. It's an agent to mimic user operation on a component.
Searcher
To retrieve ZK component with ZK selector syntax supported in SelectorComposer
For available selector syntax, please refer javadoc or Small Talks/2011/January/Envisage ZK 6: An Annotation Based Composer For MVC


We write the test case with JUnit 4 annotation, please refer to JUnit 4 in 60 seconds.

HelloTest.java"

//remove import for brevity
public class HelloTest {
	@BeforeClass
	public static void init() {
		Conversations.start("./src/main/webapp");
	}

	@AfterClass
	public static void end() {
		Conversations.stop();
	}

	@After
	public void after() {
		Conversations.clean();
	}

	@Test
	public void test() {
		Conversations.open("/hello.zul");

		ComponentAgent button = Searcher.find("button");
		ComponentAgent label = Searcher.find("label");
		
		button.as(ClickAgent.class).click();
		assertEquals("Hello Mimic", label.as(Label.class).getValue());
	}
}
  • Before starting a test, we have to setup root directory where ZUL pages locate by Conversations.start() . Mostly it's your web application's content root folder. In our example, we use maven default project structure. This method also starts the server emulator. (line 5)
  • As a matter of course, we start the server emulator at @BeforeClass , we have to stop it by Conversations.stop() . (line 10)
  • The first statement of a test case is to open a ZUL page, like a browser visits a ZUL. (line 20)
  • Before we can mimic a user action to a component, we should retrieve a ComponentAgent. Empowered by selector syntax, Searcher.find() is a powerful tool to retrieve it. Because the ZUL contains only 1 button, we can just find by component name: find("button") (line 22)
  • As we don't have a browser screen to view, we cannot interact with a component by mouse's pointer. To mimic a user action, we have to convert ComponentAgent to one of operation agents. The conversion method as() will check available operation for the target ComponentAgent . For example, you cannot type something in a Label. (line 25)
  • To verify test result, we also have to convert ComponentAgent to a ZK component then get its property by getter methods. (line 26)

Test a CRUD application

For now that you should have know the basic usage. Let's take a look at a more real case: a simple todo list application. It allows us to add, update, delete, and view todo items. Each item has 3 fields: item name, priority, and date.

Smalltalk-MimicLibrary-todolist.png

todo.zul

	<listbox id="listbox" rows="4"  model="@{win$composer.allTasks, load-after='add.onClick, update.onClick, delete.onClick'}" >
	<!-- other components -->
	</lisbot>
	<!-- other components -->
			Item:
			<textbox id="itemBox" 
			value="@{win$composer.selected.name, load-after='listbox.onSelect, add.onClick, update.onClick, delete.onClick, reset.onClick'}" cols="25" />
			Priority:
			<intbox id="priorityBox" 
			value="@{win$composer.selected.priority, load-after='listbox.onSelect, add.onClick, update.onClick, delete.onClick, reset.onClick'}" cols="1" />
			Date:
			<datebox id="dateBox" format="yyyy-MM-dd"
			value="@{win$composer.selected.date, load-after='listbox.onSelect, add.onClick, update.onClick, delete.onClick, reset.onClick'}" cols="8" />
	<!-- other components -->


The test case is to verify composer's logic. In our example application, there are 4 main function: Add, Update, Delete, Reset, the test case verify them one by one.

import static org.junit.Assert.*;
import static org.zkoss.zats.mimic.Searcher.*;
//remove other import for brevity

public class TodoTest {

	//remove setup and tear down method for brevity

	@Test
	public void test() {
		Conversations.open("/todo.zul");

		//find components
		ComponentAgent itemName = find("textbox");
		ComponentAgent priority = find("intbox");
		ComponentAgent date = find("datebox");

		//add
		itemName.as(TypeAgent.class).type("one-item");
		priority.as(TypeAgent.class).type("3");
		date.as(TypeAgent.class).type("2012-03-16");
		find("button[label='Add']").as(ClickAgent.class).click();
		
		//verify each listcell's label
		ComponentAgent listbox = find("listbox");
		List cells = listbox.getChild(1).as(Listitem.class).getChildren();
		assertEquals("one-item",((Listcell)cells.get(0)).getLabel());
		assertEquals("3",((Listcell)cells.get(1)).getLabel());
		assertEquals("2012/03/16",((Listcell)cells.get(2)).getLabel());
		
		//update
		listbox.as(SelectAgent.class).select(0);
		//verify selected
		assertEquals("one-item",itemName.as(Textbox.class).getValue());
		assertEquals((Integer)3,priority.as(Intbox.class).getValue());
		assertEquals("2012-03-16",date.as(Datebox.class).getRawText());
		//modify the todo item
		itemName.as(TypeAgent.class).type("one-item modified");
		priority.as(TypeAgent.class).type("5");
		find("button[label='Update']").as(ClickAgent.class).click();
		//retrieve Listitem again to verify it
		cells = listbox.getChild(1).as(Listitem.class).getChildren();
		assertEquals("one-item modified",((Listcell)cells.get(0)).getLabel());
		assertEquals("5",((Listcell)cells.get(1)).getLabel());
		
		//reset
		listbox.as(SelectAgent.class).select(0);
		assertNotNull(itemName.as(Textbox.class).getValue());
		find("button[label='Reset']").as(ClickAgent.class).click();
		assertEquals("",itemName.as(Textbox.class).getValue());
		assertEquals((Integer)0,priority.as(Intbox.class).getValue());
		assertEquals(true, date.as(Datebox.class).getValue()==null);

		//delete
		assertEquals(2,listbox.getChildren().size());
		listbox.as(SelectAgent.class).select(0);
		find("button[label='Delete']").as(ClickAgent.class).click();
		assertEquals(1,listbox.getChildren().size());
		
		//The next line causes IllegalStateException: Components can be accessed only in event listeners
		//find("textbox").as(Textbox.class).setValue("abc"); 
	}
  • We can use "import static" syntax to make source code shorter, because we use Searcher.find() and Assert.assertEquals() heavily.
  • When typing in a Datebox, you should use the date format that you specify in Datebox "format" attribute. (line 21)
  • The first child (index 0) of listbox is listhead (if it has listheader) not the listitem. (line 26)
  • Notice that ZK will replace listbox's children component when re-rendering it. Therefore we cannot reuse cells variable for verification, it holds old data. We should retrieve listitem again to verify its properties. (line 42)
  • Watch out! You should not manipulate component's properties directly in a test case. (line 61)

Summary

Mimic library is a unit test library that help agile developers assure quality of composer (or ViewModel) and ZUL. Developer can write test case to mimic user interaction then verify result by inspecting component's properties. It loads ZUL pages and runs the test case in a server emulator environment without deploying to a real application server. This reduces test running time largely which is very suitable for test-driven development or agile software development.

Download

Example application




Comments



Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License.