Samples to give you a jump start
The samples should give you an easy jump start. You can copy/paste them from this page into your editor.
We will start with the easiest examples and explain more advanced topics as we proceed. The description of every sample is based on the preceeding examples.
This page only shows very few of the available steps that can be used with Canoo WebTest. See the various Syntax Reference pages (e.g. Syntax Reference - Core Steps) for more details about the steps. In particular, Syntax Reference - PDF Steps has usage samples for the PDF Steps.
This page assumes that you have already followed the Install instructions.
Simple test
The first simple example shows how to connect to a webapplication starting at http://www.myserver.com:8080/myApp/login.
<property name="webtest.home" location="C:/java/webtest" />
<import file="${webtest.home}/webtest.xml"/>
<target name="wt.testInWork">
<webtest name="my simple Test">
<invoke
url="http://www.myserver.com:8080/myApp/login"
description="get Login Page" />
<verifyTitle
text="Login Page"
description="we should see the login title" />
</webtest>
</target>
</project>
Look above the import task. It is crucial that you replace C:/java/webtest with your WEBTEST_HOME installation directory. Otherwise, Canoo WebTest may not find its implementation. You can also provide this value as a relative path, e.g. a value of "../webtest" is convenient if your SimpleText.xml is stored in a directory next to your WEBTEST_HOME.
Put this file where you would like your tests to be, open a command shell in that directory and type:
Organize your tests
The import statement in the previous example should be executed only once and not be present in all test files to avoid memory problems. For this reason it is wise to organize tests in a subfolder as done in the sample project created by wt.createProject and call the real tests from the main build file
<property name="webtest.home" location="C:/java/webtest" />
<import file="${webtest.home}/webtest.xml"/>
<target name="wt.testInWork">
<ant dir="tests" file="allTests.xml"/>
</target>
</project>
<target name="all">
<ant file="testFoo.xml"/>
<ant file="testSomething.xml"/>
<ant file="testSomethingElse.xml"/>
</target>
</project>
Include files
It is important to avoid duplications to keep tests maintainable. This can be achieved with the usage of entities (or with macros). Entities are standard XML features allowing to refer (external) xml fragments through a DTD.
webtest.xml provides facilities to make work with entities and DTD easier: a DTD file dtd/Project.dtd is automatically created to reference the files contained in the includes folder.
This means that when your includes> folder contains a file like this:
url="http://www.myserver.com:8080/myApp/login"
description="get Login Page" />
<verifyTitle
text="Login Page"
description="we should see the login title" />
WebTest will automatically generate dtd/Project.dtd containing a reference like:
Referencing this DTD in your tests allows to make usage of the entities:
<project default="test">
<target name="test">
<webtest name="my simple Test">
&goToLogin;
<setInputField forLabel="Login" text="John"/>
<setInputField forLabel="Password" text="secret"/>
<clickButton label="Login"/>
...
</webtest>
</target>
</project>
Property Usage
You can use the full range of ANT features to deal with properties. A typical example is that you use a url that has some common prefix but is extended with different parameters. Using a property for describing the common prefix makes your tests both: more readable and easier to adapt to changes.
<property name="url" value="login?scott="/>
<target name="main">
<webtest name="myTest">
&config;
<steps>
<invoke
description="bad login"
url="${url}wolf" />
<verifyTitle text="Sorry, bad login" />
<invoke
description="proper login"
url="${url}tiger" />
<verifyTitle text="Welcome" />
</steps>
</webtest>
</target>
..
This opens quite a number of possibilities.
- Entity Modules
- When extracting a block into an external file as shown above, you can still use the ${property} syntax. This makes external files more reusable in different contexts. They can effectively become modules that capture the structure of the steps you are executing.
- Property Files
- If you have a 'family' of properties that change values together, e.g. label.a and label.b both for english and french, then you can create two files: english-labels.properties and french-label.properties and select it via <property file="english-labels.properties"> in your webtest. The files themselves contain the properties in the format name=value one at a line. See the ANT documentation for more details.
- Immutable Properties
- The value of a property cannot change once it has been set. While this is sometimes annoying it makes for quite a nice way to reuse a test that depends on properties. In the above example we could set the property "url" from a caller of the test target to a different value. A caller can use the <ant> or <antcall> tasks to do that (using nested property elements). See the ANT documentation for more details.
Putting it all together
Let's stick to our login examle. Say we want to create a "Login" module. It could look like this:
description="goto start page"
url="${start.page}" />
<setInputField description="set user name"
name="username"
value="${user}" />
<setInputField description="set password"
name="password"
value="${login.ok.password}" />
<clickButton
label="login"
description="Click the submit button" />
<verifyTitle description="Home Page follows if login ok"
text="${login.ok.title}" />
This should be reasonably self-explanatory. Note that you can use xml comments at any time, but they do not get reported. Therefore, I like it better to use the description for commenting.
There will be a lot of Use Cases using this module. Here is one.
<!DOCTYPE project SYSTEM "../dtd/Project.dtd">
<project default="test">
<target name="test">
<webtest name="loginAndStep">
&login;
&step;
</webtest>
</target>
</project>
Other Use Cases will be different in what they do after the login. They are likely to share even more modules, e.g. "step". They will differ in how they assemble the modules and what they do in between the module calls. How do we make sure that all use cases get executed? We collect them in a test suite:
<project default="testSuite">
<property name="start.page" value="myStartPage"/>
<target name="testSuite">
<ant antfile="loginAndStep.xml"/>
<ant antfile="useCase2.xml"/>
</target>
</project>
However, the Use Cases do not change in structure for different languages. Only the labels change. We put those languages in different property files.
login.ok.password=tiger
login.ok.title=Welcome
login.ok.password=fleur
login.ok.title=Bienvenue
In Order to properly test all Use Cases for all languages, we build a test suite that calls the AllUseCasesTestSuite for each language property file.
<property name="suite.xml" value="allUseCases.xml" />
<target name="testSuite" depends="testSuiteFrench,testSuiteEnglish" />
<target name="testSuiteFrench">
<ant antfile="${suite.xml}">
<property file="properties/french.properties"/>
</ant>
</target>
<target name="testSuiteEnglish">
<ant antfile="${suite.xml}">
<property file="properties/english.properties"/>
</ant>
</target>
</project>
For keeping the tests manageable, proper naming of your test files, entities, and properties helps much. The same holds true for the directory structure. The structure used above allows to use webtest.xml propertly but it is in no way mandatory. In short it looks like this:
dtd
includes
properties
tests
Following the proposed strategy of removing duplication in the tests will enable you to keep your tests managable and flexible enough to keep up to speed with application development. The goal is to keep every file understandable and comprehensive for its own, at its own level of abstraction. Sure this goes at the price of not having a flat view over the test "storybook". However, this can be achieved 'after-the-fact' by using the builtin reporting features. See the "Build Info"."Selftest Report" for an example.
You should now be able to tackle even more complicated scenarios like different datasets in local, test, and integration environments.
Rules of thumb
- Strike Two - You're Out!
- This is hardball. As soon as you find yourself using code a second time, don't copy but refactor. Put it in a property, an own ant file, a separate target, or a module (external entity).
- Keep targets short
- Remember that you can call every target separately. Putting all your tests in one target limits your options of running selective tests.
- Use description
- When writing the description think what message would help you if this step fails.
- Fail first
- Assure that the test fails as expected and watch how it fails, i.e. make it fail with a meaningful message. This is a mean of "test-the-test". Sometimes it is useful to even keep a negative test in a "not" step. You will find lots of those in the selftests of Canoo WebTest.
- One test at a time
- Only write one test at a time. Make it fail, make it run.
- Use a proper editor
- Take that little extra time to set up your editor such that it recognizes the WebTest.dtd. This will payback multiple times.
- Learn XPATH
- Make yourself familiar with the XPath syntax. This will enhance the power, flexibility and clarity of your tests by far. Use the XPath Explorer to make your life easier.
- Database Setup
- If your tests rely on a specific population in the database, make sure, this population is reconstructed right before the test. Look at DbUnit on how to achieve this.