The Dawn of ZK Application Test Suite:Mimic Library

From Documentation

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, they therefore also perform unit tests frequently to ensure the software quality. In ZK-based applications, it is hard to execute an unit test on the composer which is tightly-coupled to ZUL because it is instantiated when a ZUL is requested by a browser. The same problem arises if you want to verify a ZUL's zkbind expression with ViewModel. Hence TDD (Test-Driven Development) cannot proceed under this situation.

In some cases, agile developers may deploy their web applications to a server and test it within a browser. However, writing an automation test to control a browser is an issue, and testing for different browsers is also a trouble. Not to mention that running an unit test in an application server is time-consuming and no doubt an agile developer's darkest time. But, don't be depressed, let me enlighten your path with the first light of ZK Test Suite - Mimic Library.

Mimic Library : No Server Test

Mimic library enable testers to test their composer without an application server, and of course without a browser, either. Through this library, testers 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. Testers can verify the results by checking component's property or model.

No deploying to server, no rendering on browser, the unit test case can be executed in a very short period of time - this is very helpful for frequent unit testing during agile development processes.

The concept is as follows:

Smalltalk-MimicLibraryConcept.png

Tester writes test case to simulate user action like clicking or typing with operation agents. The operation agent communicates with server emulator and trigger composer's event handlers to change component's status. Tester can check component's properties from component agent 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

For simplicity, you could just download the example project we provide and give a try to write some test cases in it.

If you want to use mimic library in your project, you have to include all zats-*.jar and jetty-*.jar under example project's "/lib" folder first.

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 diving into source code of test case, 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 and emulator.
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();
	}

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

		ComponentAgent button = Searcher.find("button");
		ComponentAgent label = Searcher.find("label");
		
		//button.as(ClickAgent.class).click();
		button.click();
		assertEquals("Hello Mimic", label.as(Label.class).getValue());
	}

	@After
	public void after() {
		Conversations.clean();
	}
}
  • 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 15)
  • 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 17)
  • 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. If you try to convert to a non-available operation agent, you will get an exception. (line 20)
  • For convenience, ComponentAgent provides shortcut methods for most-used operation like click() . It just converts for you. (line 21)
  • To verify test result, we also can use ComponentAgent.as() to convert it as a ZK component then get its property by getter methods. (line 22)
  • We should call Conversations.clean() to clear desktop before opening another ZUL. (line 27)

CRUD Application Test

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" >
		<listhead>
			<listheader label="Name" />
			<listheader label="Priority" width="50px" />
			<listheader label="Date" width="90px" />
		</listhead>
	</lisbox>
	<!-- other components -->
			Name:
			<textbox id="itemBox"  cols="25" />
			Priority:
			<intbox id="priorityBox" cols="1" />
			Date:
			<datebox id="dateBox" cols="8" format="yyyy-MM-dd"/>
			<button id="add" label="Add" height="24px" />
			<button id="update" label="Update" height="24px" />
			<button id="delete" label="Delete" height="24px" />
			<button id="reset" label="Reset" height="24px" />
	<!-- 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.

TodoTest.java

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

public class TodoTest {

	//remove setup and tear down method for brevity

	@Test
	public void test() {
		//visit the target page
		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");
		itemName.type("one-item");
		priority.type("3");
		date.type("2012-03-16");
		find("button[label='Add']").click();
		
		//verify each listcell's label
		ComponentAgent listbox = find("listbox");
		List<ComponentAgent> cells = listbox.findAll("listitem").get(0).getChildren();
		assertEquals("one-item",cells.get(0).as(Listcell.class).getLabel());
		assertEquals("3",cells.get(1).as(Listcell.class).getLabel());
		assertEquals("2012/03/16",cells.get(2).as(Listcell.class).getLabel());
  • When clicking "Add" button, it adds one item to the listbox.
  • We can use "import static" syntax to make source code shorter, because we use Searcher.find() and Assert.assertEquals() heavily.
  • As you learn in previous example, this is a shortcut method. The complete calling is previous line. (line 21)
  • When typing in a Datebox, you should use the date format that you specify in Datebox "format" attribute. (line 23)
  • Find listitem to get listcell. (line 28)


TodoTest.java

//continue from previous code segment	...

		//update
		listbox.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.type("one-item modified");
		priority.type("5");
		find("button[label='Update']").click();
		//retrieve Listitem again to verify it
		cells = listbox.findAll("listitem").get(0).getChildren();
		assertEquals("one-item modified",cells.get(0).as(Listcell.class).getLabel());
		assertEquals("5",cells.get(1).as(Listcell.class).getLabel());
  • When selecting a listitem, it's value will be loaded to 3 input fields. User can click "Update" button after modifying todo item's properties.
  • SelectAgent.select(index) is to mimic selecting a listitem in a listbox. The parameter "index" is th target listitem's index you want to select and starts from 0.
  • Notice that ZK will replace listbox's children component with newly-created one when re-rendering it. Therefore we cannot reuse cells variable for verification, it holds old data. We should retrieve listitem again to verify.


TodoTest.java

//continue from previous code segment	...

		//reset
		listbox.select(0);
		assertNotNull(itemName.as(Textbox.class).getValue());
		find("button[label='Reset']").click();
		assertEquals("",itemName.as(Textbox.class).getValue());
		assertEquals((Integer)0,priority.as(Intbox.class).getValue());
		assertEquals(true, date.as(Datebox.class).getValue()==null);
  • "Reset" button will clear all input fields into default value.


TodoTest.java

//continue from previous code segment	...

		//delete
		assertEquals(2,listbox.getChildren().size());
		listbox.select(0);
		find("button[label='Delete']").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"); 
	}
  • "Delete" button will remove the selected listitem.
  • Watch out! You should not manipulate component's properties directly in a test case. (line 10)

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 Project.

The example project is an eclipse project archive. You can import it into workspace as an existing project. Test cases are under "src/test/java". You can also find the example ("hello.zul" and "todo.zul") we talked in this small talk.



Comments



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