Here I tried to give my classification of new features
available in the new major revision of the JT harness,
that we recently completed .
As I wrote
once, development of this product is primarily driven by
using it as a test harness for Technology Compatibility Kits. The next
big step in the history of the product was its adoption in
the new area of Java ME quality test
suites, specifically JDTS, the Java Device Test Suite. JDTS2.0
went out December 2006, see its DataSheet
for more information.
Among lots of other minor and major changes, this was first JDTS
version based on JavaTest
TM Harness, version 4.0.
The initial launch of the JT harness,
the Open Source
version of JavaTest Harness, was based on the current stable
version of the product, 3.2.2.
The version 4.0 was primarily driven and targeted to this release
of JDTS 2.0, due to tight time line it was developed
internally for some time and become available in open source only now
since version 4.1.1
Backward compatibility with JavaTest harness 3.2.2
Customization features.
The requirement was to make JavaTest 4 a testing platform, that can be
supplied
with product-specific functionality and have customizable functions and
appearance.
Custom splash screen can be used to provide stronger
identification of the JavaTest-based testing product.
Custom tool bars, menus, pop-up menus, preferences can be
used to associate functionality extensions with GUI
Customizable GUI rendering of a test's result - e.g. show
a
graph of some data for a test. This is targeted for test categories,
that may result
in more then just pass/fail criteria, like performance tests.
Plug-in report mechanism. It can be used
to fit the JavaTest-based test suite into the larger
testing/certification
system
Configuration process improvements
Configuration process is known as one of the most complex steps in
usage of the
large test suites, that are targeting multiple environments.
JavaTest 4 made significant steps to improve usability in this area.
New
usage models,
specific to quality vs compatibility testing area, were also addressed.
Improved configuration templates mechanism to allow
different levels of
configuration tuning.
Added new configuration interview question types
Per-test configuration, accessible through test tree
context
menu. This allows development of the test suites, where user is
required to configure only those parameters, that are minimally
necessary for
execution of specific test or group of tests and not pass through
complete configuration process for the whole test suite.
Management of test suite updates
Ability to dynamically apply updates using existing
installation of the configured testing product allows significant
decrease in cost of applying updates to
users, allowing more frequent updates and hence better product quality
Reporting
Merging report directories, generation of consolidated
report to improve support to multi-user environment.
XML formatted reports to simplify post-processing of test
results using custom tools and integration into large testing/reporting
infrastructure.
Other
Number of minor improvements, like: UI
enhancements, logging
Briefly: there are two Sun BlackBox
systems running in the world, one in Stanford, CA
by Linear Accelerator Center and another one in Moscow by Mobile TeleSystems,
one of the
largest Russian mobile operators with 74+ mln subscribers.
In classical JUnit you have multiple test methods in a single
class
that match some pattern, test framework iterates through these methods
using relection. CLDC/MIDP does not have reflection API, this is one of
problems that need to be solved when adopting JUnit-like test
frameworks to CLDC/MIDP.
There are not too many solutions to this problem, well
described in Vladimir's
blog. I would like to add few words and will describe how we
deal
with this problem using ME Framework
at Sun.
I like the elegant solution implemented in Sony
Ericsson Mobile JUnit 1.0. Absence of
reflection in CLDC (client side) sometimes can be dealt with at server
side. In this case, when list of test methods to iterate through is
static and not calculated at runtime, you can analyse class files or
sources and generate this iterator-launcher method or class.
Another solution is to use preprocessors and code generation.
This is an approach that we use at Sun for compatibility test
development for Java ME and Java SE. Test
sources are described in a meta language that allows to combine meta data
and code. Documentation and .java sources of tests are generated from
this source file, as well as code for all calls to
individual test methods. Here is the example of a generated launcher
method for MultiTest API:
protected void runTestCases() {
if (isSelected("Connector2002")) {
addStatus(Connector2002());
}
if (isSelected("Connector2003")) {
addStatus(Connector2003());
}
}
As I wrote
once, MultiTest has slightly different API then JUnit but similar
principles. It's version
for Java SE, that is natively supported by JT harness,
uses reflection. Its CLDC-compatible
variation, supported by ME Framework, requires this abstract
'runTestCases' method to be defined, in our case it is generated.
There other bonuses of code generation, like sharing compatibility tests across TCKs for Java platform API. We can have Java ME and Java SE versions of tests for the class that exists in both platforms generated from a single source.
The very common problem people meet when trying to unit-test
their
MIDlets is that you generally can not do something like this:
publicclass MyTest
extends
TestCase {
public
void test() {
MyMIDletApplication myma = new MyMIDletApplication();
assertEquals("Never get here", 7, 8);
}
}
MIDP spec prohibits calling MIDlet constructor from
application
code, for
security reasons MIDlet can be instantiated only by AMS, Application
Management
Software. All MIDP xUnit-like test frameworks, I am aware of, assume
that test execution is done by a special utility MIDlet, lets call it
MIDletTester, for example. Since it is not possible to get instance
of your application MIDlet class from the MIDletTester, unit
testing should be limited to library classes.
Here are couple of ideas, we consider implementing some of
them for
ME
Framework.
Provisioning server and instrumentation
Ideally, testing should be done on the instance, that runs in
the
environment, that is closest to real. Though you have to test every
unit of the program in isolation, it would also
be useful to have possibility to execute some tests on the MIDP
application, that is packaged and instantiated in a regular way, not on
library classes, packaged with your test application.
This can be done by adding hooks to the application, where you
can
embed your tests. This approach will require the control over the
application code, may
not always be possible.
If you supply minimalistic xUnit-like test framework with a
server,
responsible for packaging and provisioning of the test
application, you can implement a solution for this and for some other
MIDP-specific testing problem by using instrumentation of the compiled
application class files to embed whatever hooks you need. Check the
picture:
You need to modify the MIDlet class of your application under test with:
one or many methods, that will run tests. For
example instantiate a test
class by a classname and call its methods.
for each test to pass its classname, for example hardcode
to
the newly generated method or in a resource file
add a mechanizm to call these methods.
Interesting question is where calling of a test method makes sense. I
think having a UI for it, a Command is not a good idea - after all we
do all this so that testers click mouse less. Placing it into
any specific place in startRun may not work well ... may be I want
this MIDlet instance after startRun was called by AMS.
Potential approach here would be to rename all
MIDlet
methods that can be called by AMS and replace them with testing hook
methods. Allow to bypass them or call original MIDlet methods from
them. MIDlet.startUp method after instrumentation may look like:
public final void
startApp()
{
test_startUp_preconditions();
_original_startUp();
test_startUp_postconditions();
}
This article is about some changes in the ME Framework
that
were made in response to the feedback that we got from early adopters
and are available in the third development release of ME Framework 1.2
that Mikhail
just announced.
It is targeted to people who use (or plan to
use) ME
Framework or JT
harness or work in the area of Java ME testing.
Foreword
Before the open source release, we were developing and using the ME
Framework internally for years, as long as Java ME exists. As it turned
out, to start using it outside of the internal SUN environment and
supporting infrastructure is not
a trivial task. Unlikely these problems are unique to our project.
Some things became too natural for
internal users. Some approaches
that we
use internally when develop TCKs with ME Framework help to
optimize the work of the big production organization, responsible for
development and sustaining of a big number of products. It turns out
that people who need to do
a first step, like to
create a single test suite once, need more simple ways to do simple
things.
Simplest Test Suite
The Simplest
Test Suite
example,
that Alexander (aka Skavas) has recently checked into
repository, is what its name means - simplest possible test suite, that
we found reasonable for this product. It consists from three files -
ant build script, test suite .jtt parameter file and a sample test, If
you follow the instructions from
the readme
file, it will take 5 min
to build and launch it plus time to download.
I would like to go into details of two issues, that were
addressed
in the ME Framework 1.2 3rd Development release and are demonstrated in
this
sample:
Allowed alternative test formats, not limit to html test
description, that have to be created for each test.
Allowed not to provide explicit information on
what class and
resource files are
associated with test. This is necessary for automated packaging of test
applications
(bundles) and works now for simple tests.
Simple way to describe tests
The ME Framework is a plugin to JT harness
(aka JavaTest TM harness), that enables Java ME
test development and execution. This specific change was to correct
usage of JT harness features by ME Framework, specifically, TestFinder.
TestFinder
in JT harness is
the class, responsible for providing array of TestDescription
elements, that are representing test meta data in JT harness' model of
the test suite. Support of different formats of tests is done in JT
harness by plugging in corresponding extension of the TestFinder.
In short, the first change in ME Framework was just enabling TagTestFinder
in the .jtt file.
TagTestFinder uses javadoc
tags to
identify test and describe its meta information and it is a TestFinder,
used in JTReg. HTMLTestFinder
is more familiar to TCK users,
it describes tests in specially formatted html table, check here
for an example.
Simplest Test Suite uses tags to describe tests - it allows to
decrease number of files, naturally supported by IDEs and somewhat
familiar to people with JUnit experience. Check how the sample
test looks like.
Other kinds of TestFinder
Other then Tag and Html finders, the standard set of
TestFinder implementations, provided in JT harness, includes
BinaryTestFinder,
that reads information on tests to run from the
binary file. It is the one that is most often used in TCKs, where there
is a need to optimize
time to read huge test tree. BinaryTestFinder is most applicable to
cases, where test suite does not change after its development is done,
because any change in any test description requires regeneration of the
binary test data.. BinaryTestFinder is used in conjunction with
another TestFinder that
reads test descriptions from tags or html files during the build of the
test suite and stores them in the
serialized form.
It's just sort of "extension" on top of other Finders,
that"sits" on
top of them, and gets the Descriptions from other Finders and serialize
them to the binary data, and also allows to read the descriptions from
the serialized data. It can be used with any other TestFinders that
that
do the actual job of parsing the TestDescriptions from HTML, javadocs,
etc.
How to find what content to put into the .jar of the test
application
This topic is more complex and hence more entertaining one.
The problem in more details. ME Framework allows for a great
flexibility in how to turn huge pile of class and resource files of the
test suite into set of MIDP application packages for iterative
execution through autotest.
Criteria that control
creation of packages can be
max size
of the jar file
number of tests to package into the single jar
tests
themselves may describe some conditions in their associated meta data
that
would regulate how these tests need to be packaged
Tests are packaged
into .jar at runtime to allow the user to vary packaging parameters to
achieve different goals, primarily to optimize network traffic and test
execution time.
This all means - to form various application packages ME
Framework needs to know which class and resource files are associated
with each test.
These data can be calculated automatically using several
methods, I will talk about them later. What we did for this sample:
TestDescription in JT harness requires definition of the
'executeClass' parameter for every test. The value of this field is the
name of the class that is test
entry point, implementing one of supported interfaces. If
test
consists from the single .java source
file that defines single class - nothing to
calculate, right ? All class files of this test can be
described by /$executeClass.*/ expression. Note that inner classes are
OK here as well.
Other then this, nothing else happens in this sample
automatically - if there are multiple .java files, that constitute a
test, one need to
list them manually in the
'resources' field. Not that convenient as 'do nothing', but
simple to explain :) Other then 'resources' field, the standard
mechanism with
special file named testClasses.lst
still works, just generation of this file is not supported in the build
of the Simplest Test Suite.
The file testClasses.lst should be located in the special place in test
suite's directory hierarchy and containing testURL-test classes
pairs, check how
it looks like in another sample.
Approaches to automatically calculate list of classes to
package
Content of the testClasses.lst is calculated statically during the
build of
the test suite.
Approach 1 - individual test compilation.
One way to
do this is to put the load on the compiler. Compile tests individually,
set own target dir for each test, not give and test library classes on
the classpath but provide reference to their source directory instead.
All class files, that are needed by the test, will be in the target
directory of the compiler. The described approach is simple and
reliable one, we used it
for
some TCK releases. Weak places of it is that it is slow, at least in
our implementation where java compiler and preverifier were executed
through the command line for each test.
Approach 2 - parsing class files for dependencies.
We do this with a simple tool based on JINI's ClassDep
API.
It does static class analysis and should calculate all dependencies
correctly except for cases like Class.forName
is used in the tests
(which is rarely
needed).
There are probably other tools which can do the same thing.
Here is the example of the command, that can be used in the test suite
build script:
>
java -cp
jini2_1\lib\tools.jar;%JAVA_HOME%\lib\tools.jar
com.sun.jini.tool.ClassDep ^
-cp <ALL TEST AND FW
CLASSES> <executeClass> ^
-out com.sun.tck.cldc -out
com.sun.tck.j2me -out java -out sun -out
javax
In cases where all necessary classes can not be found through parsing
class files from the entry point, we used static, manually created
table, that is merged into the generated testClasses.lst. This can be
just a table with the same format, or, as mentioned above, just a
'resources' field of the TestDescription.
Limitations
Build script for the sample will work only with simple
automated
tests for MIDP. Support of distributed, interactive, OTA or CDC tests
will require more sophisticated build procedure, that will take care of
compiling SE-side components, for example.
Yet more simplification
Further simplifying of this test suite and test development
approach
is possible by making it close to JTReg and xUnit. This can be:
Minimizing set of mandatory meta data. For example, if a
test
consists from the single .java file, test entry point, that is now
specified in the mandatory 'executeClass' parameter. is known.
If this suite is used in the scenario, where tests are
actively
and constantly changing, it may be possible to eliminate 'build' stage,
as it is done in JTReg, implement test source
compilation/preverification as a step in the test execution
process.
Acknowledgment
I would like to express my appreciation to the hosting provided by that allows to link sources
for java.net projects from this blog a nice way that you can
see above.
This article is about interactive testing for Java TM
and its ME
specifics. It describes types of interactive tests that are
being
developed for Java Technology Compatibility Kits, testing of
what functionality requires user interaction. What Java ME limitations
cause problems for development of
tests, that require user interaction and how these limitations can be
worked out.
Most of definitions and examples are given using the
terminology of JT
harness and ME
Framework, but should be generic enough for the area.
For details on what is TCK, JT harness and ME Framework refer
to previous articles. Skip
the background section if you are familiar with the subject.
Background
Why not everything is automated
Interactive tests are needed to test API that produces output,
that in general case can be only verified by human or requires human or
require human input. That is API that draws something on the screen,
plays sound, or reacts to key pressing or mouse dragging.
For every specific implementation, testing of this
functionality can be automated as well with different external tools or
specific APIs. But first, not always - compatibility tests, for
example, can not rely on any specifics because have to be correct for
any compatible implementation, and second, this is a separate big
topic, to be covered in another article.
What is meant by interactive tests
From point of view of the test harness, all tests, automated and
interactive, are
discovered and executed in the same automated way. Interactive tests
are those that show a dialog with some instructions and wait for user
doing something.
These tests are usually grouped together to be executed in a single
session, separately from the rest. The rest are completely automated
tests, you can run them nightly for regression testing. Execution of
interactive tests takes hours of someones expensive time.
Requirements
Speaking from point of view of TCK
development, the most important
requirement is to make the test suite easiest for use. This means the
less interactive tests it has, the better. If we have to have
interactive tests, it is
important to make their execution simple.
To achieve this we limited number of test types that we use in
TCKs to very few. As a result, some features, that are not best suited
to be tested by these test types, require multiple test cases to be
written where we would write one 'custom' test case. The benefit is
that
TCK user has uniform interactive model, uniform interface to browse
test instructions etc. This also allows for simpler external automation
system development.
Types of TCK interactive tests
As mentioned before, such tests may require input from the user or
require some output to be evaluated, or both. Test status may be
calculated automatically or require user judgment. The interactive
test library, that is included into ME Framework, provides
Done
and
Yes/No
interfaces to enable these two types of user interaction. There is also
Info Only interface , that can be used if the end
of test is known beforehand (event sequence is predefined).
Note that these tests are not just set of user instructions
'do this - verify that', they include test code that can do most of
work.
Java ME Specifics and Solutions
PJava story - first TCK alt bundle
Interactive tests created for Java SE TCKs are usually
interactive applications, that run on the platform under test and show
user instructions and test panel in a single window. This approach does
not always work for Java ME for many reasons. First time we started
doing interactive tests in the world of consumer devices, that was
Personal Java, we found that tests we created can not be
passed on PJava devices with single Frame limitation and small screen -
test instructions and test panel were placed in the container without
scrolling capabilities, these 'Done' and 'Yes/No' buttons may not
appear on screen in some circumstances. To address this we issued first
'alternative TCK test bundle' that just enabled scrolling. After that
passing of interactive tests became possible, though not convenient.
Check how
AgentFrame
interface looks like on
PJava
with Truffle toolkit. The scheme of these interactive tests is the one
that is still used in Java SE TCKs, can be described as follows:
Figure I. Simple Interactive Test.
MIDP TCK 1.0 interactive tests
Interactive tests for MIDP TCK 1.0 were executed using the
same
Autotest
mechanism as regular
automated tests, the difference was that interactive tests expected
some user actions and were grouped together for convenience. These
tests were developed using
brand-new MIDP API and same approach that was used in JCK and PJCK.
Instructions, test panel, all user interface components
of these tests were displayed on the micro screen of MIDP 1.0 micro
devices. Given big number of interactive tests, that were necessary to
verify MIDP 1.0 GUI API, running MIDP 1.0 TCK on a regular
basis during the development process, was a headache.
You can see the screen shot of the MIDP 1.0 emulator to the
right. Click
on it to see the sequence of screens that constituted the
MIDP TCK 1.0 interactive test. As you can see, there is a big
number of
interactions, that are not related to execution of the test but for
scrolling, switching controls etc.
Distributed Interactive test framework
MIDP TCK 2.x interactive tests
To address this problem of inconvenience of interactive tests
on MIDP devices with small screen, the solution was very simple and
usability improvement was huge. Briefly, these tests were rewritten to
using Distributed Test library to have minimal functionality on the
device and have user instructions and controls, related to the test
logic, on the server part. Now to run tests on the device one need to
stare to the desktop monitor, read instructions, press some
buttons on the desktop, for example, to initiate tested process on the
device, do some interaction with the device as necessary, state
pass/fail result on the desktop if needed.
The important feature of Distributed Test framework, that lies
underneath new Interactive Test Framework is that there are java
components of the test, that reside on server and client sides and can
work together to calculate test result. One can use server side
technologies in the test, for example, for reference purpose to verify
that same technology works properly at Java ME side.
The scheme of distributed interactive test can be described as
follows
:
Figure II. Distributed
Interactive Test.
In the
example
of the interactive test for sound, you can see all GUI of this test.
Device part of this specific test does not have GUI at all, all that
device does - produces sounds that are initiated from the server side,
pass/fail criteria is specified on the server side of the test as well.
PBP TCK 1.0 interactive tests
Same solution was used for interactive tests for Personal
Basis Profile TCK. Though PBP API is subset of J2SE API, reuse of JCK
tests was not possible there - as I mentioned, these tests combine in a
single application all instructions and controls, that were not
available. PBP does not have Panel, Button - no any UI widgets, only
Component, Container and Window Frame. To reproduce anything on the
device screen we would have to draw it using graphics primitives from
scratch and creating UI toolkit was not in the scope of the TCK.
Separating functionality and interaction between server and
client parts of the tests, that were created using Distributed Test
framework, worked well for PBP. In the example
of the keyboard test you can see the same situation as in already
referenced MIDP TCK 2.0 example,
all GUI is on desktop screen, device does not have any GUI, just
accepts key presses and pass them to the server side.
AGUI TCK 1.0 interactive tests
Yet another special solution to workaround small device screen
was implemented for AGUI TCK 1.0.
AGUI stands for Advanced Graphics and User Interface, that
assumes lots of interactive tests. For AGUI the execution model for
interactive tests was also the same as for regular automated tests, all
tests were executed in the same Agent, interactive tests grouped
separately from automated. Read here
about MIDP and CDC execution modes of ME Framework.
As AGUI API is a subset of Java SE API, specifically, Swing,
our goal was to reuse
as much of JCK interactive tests for this API as possible. The reason
here is not only time saving, it is also an additional way to ensure
compatibility across different Java platforms.
What
we did is we again separated tests to different pieces that could be
displayed separately and organized test UI as Tabs. It was relatively
easy to do, since JCK interactive tests library assumed some
structuring, there was implementation of this library done with Swing
subset, that fit into AGUI API. Though it was still
necessary to do extra clicks to switch between different tabs and
sometimes scroll through the tab, the effect was a significant
usability improvement comparing to having everything in the same window
altogether.
You can see the screen shot of the AGUI 1.0 emulator to the
left. Click
on it to see the sequence of screens that constituted the AGUI TCK 1.0
interactive test.
It was a temporary solution, once we structured tests to
independent pieces, it was easy to execute these components on
distributed components. This was not a conversion of simple interactive
tests to distributed tests but a special execution framework, that
could execute simple interactive tests in the distributed way and gave
some other minor usability improvements. Overall, Interactive tests in
the AGUI TCK 1.0 when it was released looked exactly like all other
distributed interactive tests for Java ME.
Tests with static image
This type of tests is very easy to create, execute and automate.
Basically, the scenario of these tests is to show reference image and
its verbal description somewhere, initiate drawing of the same image on
the device and ask user to validate the output.
This approach is natural one, it can be used to test 80% of
functionality, related to user interaction. Some technologies use it as
the only approach for testing, for example W3C SVG test
suite. It can be used to test low level graphics and
behavior of high-level user interface components.
Even when these tests are too primitive and require multiple
test cases to be developed when few more sophisticated ones could be
enough, the simplicity of development and execution,
possibility to have consistency across many tests could be a reason to
use this approach even when it is not the most convenient.
Static image tests with ME Framework
To simplify test execution we display multiple images, related
to the same functionality, in a single window with test
instructions. Every reference image is accompanied with a Test button,
that initiates reproduction of this image on the device under test, ad
verbal description. Check the example, the screenshot of the
instructions dialog
and
device side
for tests for Java Binding to Open GL ES API (JSR 239) .
Combining multiple related images that could be switched in
any sequence allows not only for comparison of the result on the screen
with reference, but also for checking of transition one image to
another on the device. This, as well as verbal description of the
scene, may be important when reference images were done on the
implementation, that is radically different with one under test and
comparing of test and reference image alone can not provide
confidence that tested functionality behaves correctly.
Curious how much Java is a test-driven technology ?
Few words for a background.
The Java TM Compatibility Kit (JCK) is
a test suite, used to
verify if the Java standard is correctly implemented. The first JCK
came out together with the first JDK from SUN, now this effort evolved
into the industry-wide Java
Community Process.
The JavaTest TM harness is a test
monitor, used in first versions of JCK, then across multiple Java
Technology Compatibility Kits (TCK), now evolved into a general
purpose open
source test harness.
How it started
With permission of Jonathan
Gibbons, who was
around when Java was born, here is his story of the JavaTest childhood:
JavaTest started round about JDK 1.0.2, JCK 1.0.2a was
applet-based and did not use JavaTest; JavaTest was
introduced in JCK 1.0.2b.
It definitely was not the first application written in Java,
but it is true that testing was important to Java from the beginning.
JavaTest is sufficiently old that we had to develop many GUI widgets
ourselves, and one of the early JavaTest developers (Tim Prinzing)
went
on to become a significant member in the Swing team. It is probably
reasonable to say that Tim pioneered light-weight components.
Curious how it looked like back then at early JDK times ?
Check here.
You can see that testing is one of keys that
brought Java platform to where it is now.
Java's way of compatibility testing, that is having high quality
TCK required to pass to get Java logo, is how Write Once Run
Anywhere is
achieved, it is the cost of application portability and
platform
standardization.
On the road
Inspired by the conversation at David
Herron's Blog, I was
looking for analogy to illustrate the value
of compatibility testing
in the Java ecosystem, here it is - Java is
a road,
compatibility testing is its pavement.
Applications
are vehicles and the hard cover on the road makes it
possible to drive
fast.
For Java ME platform, its fragmentation
is a freedom to
choose
number of wheels, engine, use a bicycle or a truck. Another
part, the 'dark side', is where the road cover has holes, caused by
bugs in specification and implementations, test coverage problems.
Services are built
around the road to take care of vehicles and holes, like JDTS
and Java Verified,
while the road has its pavement (TCKs),
differentiating it from deserts, forests and swamps.
Testing session at Java ME track at SUN TechDays, Saint Petersburg
If you speak Russian, check the agenda
and descriptions
of Java ME sessions. 'Java ME Testing' session description is in the
end of the list, it concludes the Java ME track and Day 2.
Slides and description for it were first created in the native
language
of Internet and IT, that we use at work and call English by inertia. I
did a first pass of translation to Russian and found that for many
notions I do not have adequate words. For example, does open
source mean the same as открытый код ?
From the other side - with mother tongue you can make your speech so
alive !
Check blogs of my colleagues who are speakers at the
Java ME
track: Danila
(CLDC), Petr
(CDC), Alexander
(Testing). Presentations in English, like one of Simon Ritter
about ME Gaming, will be translated online.
I will also be there at the Java ME POD. See you at SUN
TechDays in Saint Petersburg !
As a follow up to the past article about Debugging with ME Framework, here is the the guest post from Alexander Alexeev (aka Skavas) on the new feature
he has integrated into the ME Framework,
the Interactive MIDlet agent. The feature addresses some usability
issues of executing large test suites on mobile devices, provides
on-screen indication of the testing progress and allows to perform some
operations with test results on the device.
Background
The Introduction
article described the approaches, used for execution of large test
suites for Java TM ME implementations as well as some of techniques,
allowing to optimize test execution time. To restate the main
points, relevant to this debugging topic:
test execution is managed at the server side
the test execution process consists of sequential
downloads of test MIDlet suites to the device
during this process AMS and MIDlet suites
exchange control messages with test harness
one of optimizations, allowing to minimize network traffic
and number of downloads/installations/runs/removals, is to package
multiple tests into a single bundle.
The diagram describing this autotest
cycle can be seen here.
The 'autotest' approach allows to achieve the
sufficient level of automation, that is one of high priority requirements
for test suites we develop with JT harness
and ME Framework.
User interactivity here still may be desired in few situations:
'sendTestResult' may not be executed for some reason. For
example, because of the VM exit or test/VM hang up. Since this
operation is executed at the Test level, and Test may consist of
multiple test cases, all information from actually executed test cases
may be lost. It will be unknown which test case caused the problem.
when the device is slow and optimization is used (multiple
tests in bundle), the whole test cycle will be shorter, but every
individual test bundle will take time to execute. Without visual
indication it may be hard to distinguish if tests are being executed
that slow, or it is just device stopped responding an hour
ago.
if test hung, it should be possible to cancel it
with minimal impact on the execution process,
without stop/restart the whole test run.
One solution for these debugging problems is using the Test
Export feature
to
run tests isolated from the test harness environment. Test results
from standalone execution are not sent to the JT harness, they are
displayed
on the device console, if there is such available.
Interactivity for Automated Tests
The proposed solution for all above problems is to introduce
interactivity at the device side. We added an option to use Interactive
MIDlet Agent for test execution, that provides the following features:
shows the current status on the device display
continuously saves
the current status of the RMS
provides a control for saving the current status of
the RMS
allows viewing results stored in the RMS
provides a control for canceling the
current test/test bundle and starting the next test/test bundle
These interactive features are also available in the Test Export mode.
User Interface
Additional set of standard configuration questions were added to the ME
Framework Configuration Editor. To make ME Framework to use this
on screen tracing functionality, see the screenshot
.
When the JT harness executes tests with these configuration
settings,
the user interface on the device side displays the following
information and commands:
Information string with a common count of tests done, a
count of failed tests, and a count of passed tests
Information about the current test running
Commands to cancel
the test/test bundle and to save the results to the RMS
As you can see here
,
this new interface resembles the interface of device-side harnesses,
that are available for execution of mobile
variations of JUnit.
To view results stored in the RMS, use the
RMSReader MIDlet application. It has a simple interface that uses
a Command to change the display either to "view log" or to "view ref"
output.
Open Issues
There should be better solutions then one that we chosen for canceling a hanging test.
The 'cancel test' functionality requires each test to be run in a
separate thread. Since Connected Limited Device Configuration has no
method to interrupt threads in order to break test execution and
proceed to the next test, a special flag is used to mark the test
thread as canceled. The canceled thread is set to minimum priority and
the agent starts to execute the next test.
What to do when
tests of JavaTM ME implementation test suite
fail ?
This article offers some suggestions for debugging test
failures - with
a special focus on the JT
harness and ME
Framework features that support debugging. My initial
motivation for writing this article was to announce improvements in the
Test
Export feature, however the topic is just so entertaining that
I couldn't stop there. :-)
Debugging
in
Java Micro Edition (ME) has number of challenges. Issues related to
debugging problems in Java ME implementation can include any of the
following items:
The problem can reside at the Java layer or in the native
code.
Mobile device is usually a component of a larger
system rather then isolated system.
For example, this may be
connectivity of
different kinds, integration of mobile application with server-side
components.
Multiple technologies and standards are involved.
For
example,
the CLDC/MIDP implementation may communicate with
javacard using SATSA
and with Java SE/EE using RPC API of jsr172
The device might not provide access to the Java console or
support of debugging protocols.
In addition, automated test suites do not automatically simplify the
problem of debugging, but
instead add their own set of unique complexities. The fact that some
tests fail might not
provide enough information to help you identify the problem. Often it
can take time and require a certain certain amount of
effort to determine what is wrong.
Problems, specific to automated Java ME test suites, have the
following roots:
Automated test execution on CLDC/MIDP requires special
AMS mode, autotest.
CDC/PBP execution mechanisms may be complex as
well. Basic information on this topic can be found in the first
article: Introduction
to Java ME Testing Tools.
The distributed test execution mechanism.
This includes
execution of a test with test harness (JT harness) running on the
desktop and the test
agent is running on the device. In addition the distributed tests
themselves consist of multiple components (such as SE and ME
components).
A complex configuration
mechanism.
Before starting to run
tests you need to configure test harness according to the environment
and implementation under test. This complicates the debugging by making
the whole system more integrated. Tighter integration makes it
difficult to identify the problem by isolating the piece of the test
code from the test harness.
Debugging Tips
The goal of this section is
to provide you with a list of practical steps that could be taken by
the ME
Framework and JT harness user in the process of analyzing test
failures. These debugging tips range from know-how to very natural and
evident.
Tip 1 - Browse the code, test specification, test output.
If tests are written well, atomic, documented, provided with good
trace information, if type of failure allows this trace to be viewed at
the
console or in the test result, stored by the test harness. If all these
'ifs' are there, it is enough to look at test spec, sources and output
to identify the
problem.
It is not rare case, btw. Example
of JT harness test result file contains all information, that test
harness could provide to help with debugging, has sections for:
recognized parameters of Test Description
values of environment variables
version
time stamp
exact command used for test execution
test output itself
lots of other stuff, useful and not
As I can see, other then standard, old-style .jtr files and
reports,
most of teams working actively with JavaTest TM
harness-based test suites use reports, customized for their needs and
type of work they are doing.
Tip 2 - Turn on logging
In the ME Framework, you can configure the logging level in the
following places:
Logger API used by the ME Framework implementation classes.
'Debug output' options for ME Framework components
Turn on Logger
This type of tracing is available for the server side of the ME
Framework. It is more useful when identifying problems with
the ME Framework than
when debugging problems with tests. To identify problems with the
framework, you need to understand what is going on
with the internals, what test filters are used, etc. It can also be
useful when debugging problems with types of tests that use some
service run
by the test harness.
To turn this type of
logging on you need to specify the config file through java system
property when starting JavaTest harness, like this:
With the following example
of a log config file,
you will have this type of
content on your console.
ME Framework Tracing Capabilities
As previously mentioned, one of problems here is that the entire system
is distributed. Each major piece of functionality is provided by
several
components, working on both the harness and the device sides. To be
able to
track process steps, it is possible to turn on logging of debug
information to console for every subsystem. These subsystems are listed
below. Each of them has nice illustration in the ME
Framework
Developer's Guide (1.5Mb) and in the following text I have
referred to the corresponding
pages in that
document.
Test
execution subsystem (CLDC/MIDP), Figure 3-4 at page 27.
The trace lists control messages between the harness and the device
that
correspond to Autotest
execution flow. This may be useful if test execution is very
slow, like when
there are multiple tests packaged per test bundle, to make sure that
there is a progress, to find which exactly test crashed the VM, to see
exact test parameters and test result outside of the harness. The
real-time trace can be observed on the device console, if the console
is
available. See a snapshot
from the Configuration Editor that shows which Interview questions are
responsible for this option. Check server
and device-side examples
of trace output.
Distributed
test framework, Figure 3-5 at page 29.
Here you can see all messages exchanged by this framework, who sends
what. Needless to say, it is one of the important features used to
investigate failures of
distributed tests. Simple interactive test with 3 static images sends that many messages to
pass.
Agent
(CDC/PBP).
Passing '-trace' option to agent displays everything going inside of it
at
the console (if available). This is a standard feature of the JT
harness
Agent. The example of the
Agent trace can serve as a good illustration to CDC-specific
approaches to address test suite scalability. Note the data
exchanges and test classes instantiations for every test.
When JT harness or a ME Framework-based test suite is used as a part of
automated regression testing subsystem for nightly/weekly test
execution, we turn all debugging options
on by default, to have more data ready for offline failure analysis, if
required.
Tip 3 - Execute the test standalone
The natural step of isolating the problem is isolating failing test
from the test harness environment by executing it standalone. It may be
possible in some situations to modify original test source, recompile
it, and execute in the debugger.
Each individual test usually has an application entry point,
allowing to
execute it outside of the test harness. This is usually static main()
taking
an array of
parameters (the same parameters as those passed to the test by the test
harness). You
can put test classes in the classpath and call the test by the class
name.
To get values of test parameters
you may
need to dig into test environment. To execute standalone test
corresponding to the following sample test description:
export sampleValue=<find
'sampleValue' variable in the test environment>
java -classpath $TEST_HOME/classes^
com.sun.tck.satsa.tests.api.java.security.KeyFactory.generatePublicTests^
-envValue $sampleValue
Or even simpler - JT harness result file contains the exact
command
and values of parameters that must be executed. See
section messages:(1/693)
in the example.
Unfortunately this works well only in CDC and Java SE
execution
modes. This approach will not work for CLDC/MIDP, where you
need the application to be packaged and deployed before you can execute
it.
Tip 4 - store for offline analysis
In CLDC/MIDP execution mode, instead of using autotest
feature, one can download individual test applications manually for
offline analysis, using web browser, for example. This can help
identify problems related to interpreting the application descriptor
and
manifest.
Tip N - use common sense
The list is not and can not be complete, yet more tips from the top of
the head:
Vary configuration parameters
Add trace printing into test itself or into tested code
Execute the test on the another implementation to verify
its correctness
...
We try many different debugging techniques all the time and very often
they work. But the most effective solution, that is supposed
to help with digging out
the most complex problems is ... Test Export.
Test Export
The ME Framework is a quite complex set of interacting
components involved in test execution. When a test is
reported as failed by the JT
Harness it's not always evident where the bug is and how to
track
it down. Most often, when users are trying to track down a
bug, they want to run the failed test standalone on
the device under test. This is where the Test Export feature
can help. Test Export converts an individual test into a small
standalone Java ME application containing the test, which can be
executed, debugged, or used in any way convenient for the user.
Getting Test Export as a side-effect of Autotest execution
A very simple, partial implementation of the test export was
available
in the ME Framework from the beginning. It was a hack of a standard
CLDC/MIDP execution mechanism., described by the following scheme.
FIGURE X. Autotest mode.
In order to turn test into CLDC/MIDP application that executes
separately
from the harness, one must replace all these arrows, representing
some message exchanges, with static data.
For the initial ME Framework implementation of the test
export feature, test packages where
supplied with all information necessary for test execution (that
replaced links 3 and 4). The execution server was packaging
test bundles
without waiting for any requests from AMS (links 1 and 2). For the test
harness, test
status indicated success of packaging and not actual test execution
(link 5). When executed, tests did not send result to the
execution
server but just printed them on the console (link 5). Tests
were packaged with all test data but not automatically downloaded to
the device and test packages not removed after execution cycle
completed.
Even this simple and limited approach allowed to solve some
troubleshooting-related tasks. For example, a QA engineer responsible
for TCK execution on the development build of the implementation could
use these exported test packages as attachments to bug reports. A
development engineer not familiar with TCK execution
could use it to reproduce the problem and verify the fix.
Test Export in
ME Framework 1.2
The previous implementation of the Test Export was not
complete. Evident limitations were that only simple
non-distributed tests were
exported and not test sources. For the user, this meant that a created
application could not be modified and rebuilt. The previous
implementation also exported only .jar files and not .jad files.
Implementing the full Test Export feature for all types of
tests is a challenging task requiring very accurate tracking of all
test dependencies. The following are examples of such dependencies:
Custom jad/manifest entries
Test specific security conditions
Code and resource dependencies of test and test suite level
Identifying all test sources associated with a distributed
network test is not a simple task. To make this feature really
user-friendly, one should provide parts of the test execution
infrastructure, such as the provisioning server for MIDP.
Many of these problems are addressed in the new Test Export
implementation that was recently integrated into the ME Framework by
Dmitry Trounine.
To initiate Test Export for a ME Framework 1.2-based test
suite, the
user should first open the Configuration Editor and, in the interview,
set test export mode on. Then the user should specify the export
directory (the location where exported test will be saved) and maybe
some additional parameters, such as the 'Prefix of URLs to JAR
files' parameter specific for the MIDP platform. See the
following screen-shot of the JT harness Configuration Editor:
Configuring Test Export.
Finally, the user should select the test or tests to export
and run them just as in a regular test run. In test export mode,
instead of executing tests on a device, the selected test or tests are
saved in the specified test export directory.
What
you get with test export?
When the test export is
done, the following
content is created in the export directory:
Java ME applications in JAR files named test1.jar,
test2.jar, etc. containing the exported tests.
Just as with any other Java application, these applications
can be uploaded on any suitable device and launched. The exported tests
are executed in the same way that they are executed by ME Framework but
in standalone mode, printing the diagnostics and test result on the
device screen.
In MIDP mode, Java application descriptors (JAD files) are
generated: test1.jad, test2.jad, etc.
These descriptors are properly configured:
They contain the same attributes as in regular test runs.
They are signed and include certificates if the test
suite was configured for trusted MIDP security mode.
They contain proper links to the exported JAR files.
You can use the generated JAD files for OTA provisioning of
exported tests by putting them on any suitable HTTP server or by using
the special provisioning server included with the
ME Framework.
Java sources of exported tests in src subdirectory.
These source files can be used for debugging or rebuilding
the exported tests.
Class files in classes subdirectory.
Ant build script in build.xml file.
Yeah! Users can change the exported tests by modifying its
sources and rebuilding them with this build script. It contains all
necessary targets for compiling sources, updating JAR files from
classes, and signing JAD files. In addition, build.properties is also
generated in the export directory. It defines properties used by the
build script and can be used to configure the build. For example,
property trusted, if defined, triggers signing JAD
files when updating exported tests.
Additional libraries and tools in lib subdirectories.
These are not part of exported tests and are not required
for using them, but can be also helpful. For example, exportSigner.jar
is a tool for updating signatures and certificates of
MIDlet suites with tests in those cases where the tests contained in it
have been modified and its JAR file has changed.
Let's look at this new feature from the point of view of a Sun
Java Wireless Toolkit (Wireless Toolkit) user. Before the test export
feature was introduced, users could execute tests on the emulator by
using its autotest mode:
This command launches the emulator and specifies an URL at
which the emulator should look for tests to download. At this URL
resides the execution server of ME Framework. The execution server
responds to 'getNextApp.jad' requests by sending new and new tests from
a large test suite. The emulator fails in a loop repeating three steps
(install, execute, remove) for each downloaded test until the execution
server has no more tests to send. There was no way to get just one test
(corresponding JAD and JAR files) for standalone execution. In
addition, users of the Wireless Toolkit know that autotest mode doesn't
allow debugging!
Now, with the test export feature, a user can select the test
to debug and export it to any appropriate location. JAR and JAD files
are generated and can be executed on emulator. The following is a
typical command for launching the exported test on the Wireless Toolkit
emulator:
During its execution, the test prints the output to stdout.
Click here to view an
example.
This time, debugging the test during its execution is easy.
Just add the -Xdebug argument to last command
with all necessary parameters. You can then use your preferred debugger
with the IDE of your choice to debug the test with its sources which
are also exported.
Future Plans
The next planned improvement for debugging support will come
from the integration of Skavas's GUI Agent. This will allow
you to use GUI and RMS in addition to console output for execution of
exported tests. Watch for more information about this in the future -
it's a topic for another post.
The Test Export feature is under development right now and you
can improve it by posting on ME Framework forums.
Propose your improvement or new feature and you may see it in one of
the next releases.
Testing Command-Line Applications using Golden-File approach
This article is addressed to those interested in JavaTest TM
harness and its open source version JT harness.
Its goal is to serve as an example of using JavaTest harness outside of
the world of productized
test suites.
The story describes our experience of using JavaTest-style
test format
and JavaTest itself as a test harness for functional and regression
tests. The tested item is a command-line application.
Background
The specific command-line application being tested is ApiCover, one of
the components provided to JCP members in the JCTT
package. Briefly, it takes a description of Java TM
API to test
and pointer to the test
classes and calculates estimation of the test coverage. The tool
supports multiple
options.
The most frequently observed approach to functional test
development for such simple cases is
to have a set of shell scripts placed into a directory hierarchy. Each
of these scripts performs one simple check and reports results to the
console. Tests are run by a trivial test harness, usually another shell
script, that performs test iteration and joint status reporting. Test
specifications usually come separately from tests.
How it was done here
In case of ApiCover the test suite was JavaTest-based. The choice was
quite natural, given the long history of using JavaTest for testing of
command-line tools, like Java compiler or
CLDC preverifier.
Every individual
test description in this test suite contains information on how to
launch the
tool and how its output should be verified. All tests in this test
suite are written using the "golden-file" approach. The golden data is:
application output streams both stderr and stdout
exit code
set of output files
The test suite execution is done using JavaTest harness and set of
trivial scripts, responsible for launching the application under test,
capturing and storing its output and
comparing the results with stored data. The main idea is to make it
simple to launch ApiCover in multiple modes and verify the result.
Result verification may be textual diff or xml validation, data storing
is optional.
The test development scenario for the new test is as follows:
Create test description, including:
test case specification (textual, optional)
parameters, comparison procedure to use
Run test in the 'setup' mode
Validate output and mark it as 'golden file'
When application is changed and test starts to fail, validate
the new output and mark it as 'golden file' if appropriate.
Test Description example:
Description
This test verifies that tool includes all
public/protected class
members into the basic report if -detail option specified by '4' value
and -format value is 'xml'.
Test Descriptions
Test cases included:
report000
title
report000
executeArgs
-apiinclude testapi -tck tcks/all/classes -api
apis/all/all.sig
-detail 4 -format xml
keywords
runtime
executeClass
diff
What it means:
Description
- Contains verbal Test Case Specification
The table
describes actual test cases that will
be executed. Description is done in the language of JavaTest's HTMLTestFinder.
Below you can see how these specific descriptions are interpreted by
the execution Script, which used for this
test suite:
title
Unique ID of the test case
executeArgs
Command-line arguments to pass to the
tool.
keywords
This field is used by main test filtering engine
of JavaTest harness. Not used in this test suite.
executeClass
Which of predefined golden file comparators to use
for this test
Pros and Cons
Pros:
All traditional prerequisites come from using a
specialized test harness, like test execution and test result
management, test specification, source, and test result browsing,
parallel test execution, test exclusion and filtering, multiple
environments support (JDK version, for example)
etc etc.
We got highly automated and maintainable test suite,
preserved high consistency through all tests
Test development is fast and simple
Application can be tested at multiple platforms by
design. When testing Java applications
that need to be verified in multiple environments, it is critical to
avoid a dependency on a specific scripting language used for test
development.
We avoided information duplication. The test code is linked
to the test
specification and a test report
Cons:
Good test harness is a complex tool that takes time to
study. Infrastructure may need to be adjusted for it.
The "golden file" approach is naturally limited, can not be
enough to cover everything
When output is unstable, this approach may not work or may
require
sophisticated comparators. The most obvious example is in processing
timestamps.
As usual, almost all of pros have drawbacks in some situations,
one size
never fits all.
This article is oriented to developers of test suites of any kind.
It provides some criteria that can be
used when choosing a test harness for certain types
of test suites. It describes
requirements that are treated as most important for JT
harness, the open source version of the JavaTest TM
harness. The ME
Framework is a JT harness plug-in for JavaTM
Micro Edition (ME), driven by the same principles.
The requirements for the quality of test suites vary depending
on the
engineer's goal, the product being tested, how many and what kind of
people will be using the test suite, how often and for how long, and
how the test suite will be maintained. These factors may vary depending
on whether you write unit tests for yourself or your project, or if, as
a member of the SQEgroup on a large
project, you are developing a test suite that will be executed by the
SQA group.
Sun Microsystems has a long successful story of
development
large
test suites of various types.
The development of the JavaTest harness
was highly
influenced by
its adoption in Java TM Technology
Compatibility Kits (TCK). The majority, if not all of Sun's
TCKs are built on the JavaTest harness. The key consequences of
this:
these test suites (TCKs) are products,
developed by one group to be
used outside of it on a constant basis for significant
period of time.
'used in all
TCKs from SUN' means that test suites built on JavaTest
harness were run on all Java-compatible implementations in the world -
just
because implementations become Java-compatible after passing the TCK.
It means a
lot !
though it is not the only area where JavaTest harness is
used,
the main focus is on testing of Java platform, not applications.
These test suites and a test harness have satisfy the requirements,
listed below:
Test suites based on JT harness and ME Framework in Java ME
case, are
supposed to be
executed on a continuous basis through the whole development cycle. In
the case
of TCKs, this means regression testing through development cycle and
certification of the completed product. The more we can automate the
better. The requirement for automation includes both providing
a complete
command line interface to the test harness and automation of the test
frameworks..
Documented
Test harness and framework documentation
The importance of having good user documentation for tools like JT
harness should
be understood. In this case 'users' means users of the final test
products,
based on these tools.
Test documentation
Productized test suites are supposed to consists of well-documented
tests, where all necessary information on each test can be
obtained not just from the test code but from the test
documentation. It is up to developers to decide whether to
provide such kind of
documentation for the test suite. The JT harness provides a
mechanism to combine both formal test descriptions and user
documentation in the same HTML document.
Scalable
Some test suites, that are built on JavaTest harness, are large.
Ideally, the
only impact from increasing the size of the test suite should be linear
dependency on resources - either time or number of devices - that are
being used for testing. There are multiple ways used to achieve this,
some were
described in the previous
article.
Reliable
Each test suite must run to completion, which means not only that the
framework code must run without errors but the test failures, if any,
must not interrupt the process. Running test suites without
interruption is an important quality criterion by itself but for large
test suites it becomes a critical requirement. Execution of a really
large test suite may take weeks, tests may run overnight. The
test engineer must be provided with as many comprehensive results after
the execution completes as possible.
Any resource
leaks or synchronization problems in the framework code are very high
priority issues.
Easy to debug
While the process of test execution is sometimes demanding, the bigger
challenge is when tests fail. There are many features intended to
simplify
failure debugging, both in the JT harness and in the ME Framework.
Debugging-related features range from providing test sources
linked to html test
descriptions and browsable from JT harness, logging capabilities,
possibility to execute tests standalone without a harness. The
ME Framework provides the features that are most critical for Java
ME, such as exporting each test to a standalone Java ME application.
Configurable
A complex test suite, that is built to test multiple products
in
multiple environments, may have hundreds
of configuration options. The configurability here is not
just providing a way to set values for these options but a
user-friendly mechanism, allowing optimization of the process and
providing documentation for your test suite settings, sufficient to
give a conscious answer to every
configuration question.
The list is evidently not complete. Comments and additions are
welcome.
The previous
article described the primary test execution mechanisms,
used in the world of Java ME implementation test suites:
'Server/Agent' approach, used for CDC implementations,
where test code is downloaded by Agent application from the Server
'autotest' approach, where tests are packaged into sequence
of applications, that are repeatedly downloaded/executed/removed.
Please make sure to familiarize yourself with these concepts, I will be
referring to them later.
Today I would like to focus on limitations of
these approaches, what
types of functionality can not be tested this way and describe several
solutions. Some of these ideas are
implemented in ME
Framework,
there are variations,
implemented in other Java ME testing products.
Talking about limitations, the main point is that using these
mechanisms one can verify what is going inside of a single application
when it is running.
These mechanisms do not allow application restarts and crashes, assume
fixed scenario and only single application running at any given time.
Note, that this is usually all that is needed to test of Java
API behavior. Just it (API) is not the only focus of standards and
testing in the Java
ME world.
Examples of Java ME standards, that can not be tested with
the above mentioned approaches, are as follows:
MIDP
OTA specification, among other things, describes
criteria, that result in an application installation failure. Tests
for these requirements need to meet these criteria and verify that installation
fails. API testing mechanisms work only
if install&run steps pass successfully.
MIDP
PushRegistry specification talks about static registration
of the Push event handlers. If application is provided with special
attributes, it gets registered in the PushRegistry to handle incoming
WMA messages, for example. Testing of this functionality assumes
the following steps are present in the test procedure:
- an application with Push registration is
installed
-the push event is initiated
- application is launched to handle
the event
The scenario does not fit into the Server/Agent scheme, because it
requires
an application installation to happen as part of the test, and does not
fit into the autotest scheme,
because it does not have automatic 'run/remove' steps, that are
mandatory parts of the 'autotest' cycle.
CHAPI
spec talks about communications between two applications,
the ContentHandler and Invoker.
Overall, there is a considerable number of JCP and non-JCP standards
that focus not only on API but on applications. Testing of these
standards requires non-standard techniques.
The cases above are usually
associated with the platform
component, named JAM (Java Application Manager) or AMS
(Application Management Software), therefore the testing
techniques that involve AMS operations (install/update/run/remove) or
application life cycle (start/pause/stop/destroy) will be referred to
as 'AMS testing'.
OTA Testing Framework
Absolute Weapon
OTA Testing Framework is an established terminology for the technique,
that was first
time used to test the OTA specification. Below is the description of
this
specific case first, followed by some analysis and
discussion of potential
alternatives.
Typically, the OTA Testing Framework consists of the following
components:
OTA test - the test scenario, that includes
standard and custom AMS operations. It operates with applications
associated with this test. It is executed on the server side of the
system,
main communication point responsible for reporting the whole test
status.
Test application(s) - zero or more pre-packaged
applications that may contain part of the test code that needs to be
executed on the device. They may communicate with the main test
scenario -
OTA test
OTA test is executed in this framework on the test harness side and
uses OTA server to publish applications:
There is also an important component called OTA Server. In
MIDP
case it is HTTP server controlled by OTA
test and responsible for provisioning of test applications. Nice
artistic
picture of the
OTA Testing Framework in provided in the
ME
Framework Developer's Guide (link
to PDF version), check Figure 3-7.
The approach described above is universal and powerful. It can
be used to test the most exotic cases. At least, so far it stays as a
last
absolute weapon used if no other technique works.
Last Thing to Use
The only disadvantage of OTA Testing Framework is that it is
terribly interactive. During the certification run TCKs do not allow to
use any automation, every AMS operation must be performed manually.
With a simple install/run/remove cycle, where one needs to read
instructions, enter url, wait for download/launch/execution
complete/remove, it takes 1 minute minimum for a test case.
Now imagine yourself a QA engineer, who has to run
CHAPI TCK,
that contains ~40 OTA tests, as a regression test suite on a regular
basis during the whole development cycle without any automation.
Lets consider a variation to the above
approach, that can be used when it is OK to narrow the scope of covered
possibilities and simplify the usage.
XletManager
This is the approach, used initially in PBP & TV TCKs to verify
parts of the specifications, related to an application life cycle. In
PBP
case it was also for testing Ixc - Inter Xlet Communication.
The idea is to specify the Java interface to the AMS that
will allow
one application to perform the life cycle operations on
another application. It was created for PBP/TV, where testing is
based on the Server/Agent model. The scheme works in the following way:
An implementation developer provides an implementation
of XletManager interface, that would allow a test application, executed
on the device to invoke the AMS operations through the Java API. In
the
general case, if Java interface to AMS is not available, the
XletManager implementation may be interactive.
Test Suite user manually downloads and installs on the
device the Agent application and a set of Xlet applications that will
be
used in tests
Tests that are executed within the Agent instantiate
XletManager and operate with additional pre-installed test applications.
While in the PBP TCK this approach is used to initiate only
life cycle
operations from the test, executed on the device, it also can be
extended to any AMS operations like install/update/run/remove.
Comparing with OTA Test Framework
Main benefit of XletManager-like approach is that it allows to
use a
single Server/Agent test execution model for the whole test suite.
With this specific approach, there is no dynamic application
installation/removal, no application provisioning component, test
applications are preinstalled before test execution begins.
There may be restrictions, that will complicate the
use of this model or just make it impossible, like:
interactive implementation of XletManager may be
complicated for devices with small screen
platform may not allow more than one application to run
simultaneously.
Variations
There are several active components involved into execution
of
the test, there may be several places where to put the main scenario
responsible for execution of AMS operations. It may be server (OTA Test
Framework) or client side (XletManager-like) of the distributed test.
It can be AMS itself - 'autotest' mode, that AMS is supposed to provide
for an automated
execution of test suites on CLDC/MIDP,
is also a scenario of AMS operations, that can be used for test
purpose.
Interface to the AMS may be implemented through plugins, that
may be provided by implementation developers. These plugins may be
interactive in general case or automated. Automated testing may be used
for QA/regression testing or even for certification in some cases.
There are interesting possibilities of using standard Java ME
APIs in order to communicate with AMS, for example CHAPI. As a minimum,
it can
be used to have the test code distributed across multiple MIDlets or
MIDlet-suites that are registered as ContentHandler-s and invoked from
the
main test scenario.
Summary
Over time, the number and complexity of Java ME implementation
tests dealing with AMS have increased. I believe this is a natural
consequence of consistent focus on standards in the area of application
management for consumer devices.
The interesting and important problem, that comes together
with number of appearing and evolving AMS-testing frameworks
that are often interactive is automation, it deserves separate
article.
This blog is based on and is about my and my colleagues'
experience in JavaTM ME testing tools and test
suite development.
It is inspired by SUN open-sourcing Java ME software stack and
Java testing tools.
Implementation Testing vs. Application Testing
Java ME developers perform their
application testing
routinely with unit tests written as part of their
development cycle.
J2MEUnit
and JMUnit
work well for this: all you need to do is
to package the test framework and all your tests with your application
and
provide an entry point to start test execution. These frameworks run
your tests in a single MIDlet run and display results on the device
screen.
This is all what the most of the application developers need.
Things change when the object of your testing is a Java ME
implementation on a mobile device (that is the entire Java ME software
stack). We will talk below about the specific challenges that
complicate the testing process.
Some of these are specific to Java ME platform, others steam from the
size and complexity of the technology.
Implementation Testing Tools
A number of tools were developed over the years to address
the implementation testing needs. Some URLs:
The first issue to deal with is the test suite scalability.
Due to the variety and complexity of Java ME technologies,
the number of tests is large.
Let's say we wrote 10000 tests for the CLDC VM specification.
If we tried to execute them in a JUnit-like test framework,
we would quickly find out that
10000 tests do not fit into a single application, you have
to split them in smaller chunks.
some tests crash the VM. If we tried to execute all tests
in a single MIDlet.startApp call, we would never see the result of any
test (even those which don't crash). You need to be able to detect VM
exits and catch any unexpected exceptions.
some tests crash the VM on purpose. These are negative
tests which verify that VM handles certain conditions properly (e.g.
throws VerifyError).
device runs out of memory because all class files of the
test suite do not fit into it (garbage collector frees unused data from
the memory, but doesn't free classes: these are garbage-collected only
together with their class loader).
tests running in the same VM interfere with each other
causing failures which are hard to explain or debug. Or tests misbehave
and lock up the VM (this is where you learn that shared resources and
race conditions are a big deal in the testing world).
you need an accurate report once the test run is complete:
if 100 tests out of 10000 failed, you need detailed information on
every failure and you don't want it displayed on the device screen.
There should be a way to load test results from the device onto your
server or desktop machine. In a perfect world test results for every
test cycle are stored in an easily accessible database.
Since tests are typically run on a device with unstable
software
stack, execution of a large test suite there is an additional
challenge. This is equally true for much more capable platforms like
Java SE. One should expect all sorts of things to go wrong:
Implementation bugs causing failures and crashes.
Resource leaks resulting in memory overflow, unavailable
file handlers and sockets.
Incomplete implementation lacking networking or user
interface support.
There are many other problems to be solved.
For example, how do you automate testing of your Java-enabled Blu-ray
player?
Let's talk about these and other problems on specific examples.
CDC and Java SE Testing Solutions
Java SE platform is where Java technology originated. Not
surprisingly, this is where the testing solutions were initially worked
out.
CDC + Foundation Profile is a platform similar in many ways to Java SE
(but without the myriad of recent extensions and features), the
approach, described below, came from Java SE and works for CDC+FP.
CDC platform is richer compared with CLDC. The most important
benefits we have is reflection APIs and user-defined class loaders.
This makes many testing tasks easier.
The most robust testing set-up proved to be a client-server
model
for the test harness: the main harness application runs in a stable
Java SE environment and a small agent is deployed on the device under
test.
The main harness application manages test suite configuration and
execution,
as well as the test result collection and storage.
The agent connects to the harness application over the network. All the
agent does is repeatedly download and execute tests (a separate class
loader instance is created for each test download) as well
as send test results back to the main application.
This effectively solves most of the problems outlined above:
Small memory requirements. All you need is enough memory
to hold the agent application and the largest test. Test classes are
garbage-collected each time test class loader is garbage-collected, so
you are not limited by the size of a test suite.
Test interference is minimized. Since tests are loaded
one-by-one, they do not affect each other and their resources are freed
once execution is complete.
No multiple application downloads during the test cycle.
There is only one small
agent application to download. The rest is handled automatically.
No test results on device. You are not dependent on file
system, you don't do detective work if the device dies. By the way,
file system independence has the added benefit of nicely handling the
security-constrained environments such as an applet.
There are several critical dependencies in this model: you
need a (stable) network, class loader and a few extra security
permissions. These may not be available everywhere by default, but this
is topic for different discussion.
CLDC and MIDP Testing Solutions
Things get more difficult on a CLDC/MIDP stack.
There is no class loader to rely on (and no reflection either).
The only universal way to load test code on the device is via
application download. While AMS (Application Management System) does
not support automation
by default, a very simple extension called "autotest" satisfies
most testing needs.
The autotest feature is a special AMS mode which iteratively
downloads, installs, runs and removes applications from a specified
URL. Test harness makes new test applications available at this URL
and the AMS picks them up.
10000 tests will be packaged into a number of test
applications.
Each application will include a small execution agent (to report test
result back to the test harness) and the test classes.
In a trivial case we will have 10000 different applications.
Shortening the Test Cycle
Test applications are downloaded over the network.
The good news for MIDP is that all devices support HTTP download.
The bad news is that some of these connections are as slow
as 9 kbit/s. It will take 2.5 hours to download 10 MB of test classes.
And there are many other things which will affect the test run
time.
Even though execution agent is small, it is bundled with every
application, wasting a lot of network traffic!
Each test bundle download requires new a network connection; these will
slow down the execution.
Test data and test results are sent back and forth between the harness
and the test application; extra network bandwidth is consumed.
Each test needs time to execute: some tests do extensive computations
and will take a few minutes to run.
Since the system is distributed, one must be minimally taking care of
proper task scheduling. For example, test applications must
already be packaged and signed when request for the next application
comes - if you start packaging task only on getting request
for
the next test application download, it may have surprisingly
sad
effect on execution time.
In the early days of CLDC TCK 1.0 (test suite, used for
certification of implementations of CLDC 1.0 specification) test
execution was taking up to 2
weeks in some environments!
With a few improvements, one can pass CLDC TCK in a few hours:
Pre-install shared agent code on the device (romize
classes of the test agent).
Package several tests per downloaded application to reduce
the number of network connections and AMS operations. Each device has a
different maximum application size so the total number of applications
will vary.
Use multiple devices in parallel. Let the harness assemble
and sort test results.
What else?
Described test execution models have certain restrictions. As example:
using Java ME application to run tests does not allow to test AMS
behaviour, that is primary focus for some Java ME specs. This specific
problem has more then one solution already, as well as there are
solutions that allow to run interactive, distributed tests for Java ME.