Showing posts with label testing. Show all posts
Showing posts with label testing. Show all posts

Monday, March 8, 2010

Android Testing - Tips

  • What is Android Context class? It's "an interface to global information about an application environment. This is an abstract class whose implementation is provided by the Android system."
  • The native Android OS support for testing is based on jUnit 3. Don't try to use jUnit 4. The results are not predictable. I had the first test run fine, but no more tests would finish.
  • Testing support:

    • Use ActivityInstrumentationTestCase2 for functional testing of a single Activity. The selected activity will be created and managed by the system as specified by the regular activity lifecycle. Tests can interact with the UI widgets to imitate user actions.
    • Use ActivityUnitTestCase to run unit tests of an isolated activity. Activity under test will not be subject to regular activity lifecycle.
  • If you see a problem of type error: device not found and shutdown the adb.exe process. It will restart automatically and try to reconnect to the device. Sometimes, starting the intended Instrumentation on emulator (an option in Dev Tools application) does it all for you.
  • If adb does not connect after restarting it (shows "DeviceMonitor]Connection attempts: 11..." and LogCat nic nie pokazuje), restart PC.

Saturday, October 31, 2009

Why TDD Rather Than Traditional QA's Writing Tests

First, I describe what is TDD. Then, I present a story that lead me to writing this article.  But if you don't care about stories, just skip to Conclusion and Resources


What is TDD?
I'll describe TDD not with my own words but with a few selected excerpts from this resource:
  • The practice of maintaining automated unit test suites has gained widespread acceptance over the past decade to the point where most developers today either engage in some amount of test writing or at least feel bad for not doing it.
  • To prevent regression, developers must provide a set of tests that exercise an application top-to-bottom and end-to-end (front-end to back-end), but anecdotal evidence suggests that even automated tests covering as little as 50% of the code can effectively guard against regression in many applications.
  • Competent developers either conform to a test-first discipline in which small test harnesses are built to exercise an API before the API itself is even implemented, or else employ a code-a-little-test-a-little (CALTAL) approach in which each unit of code developed is tested immediately after its compiled.
  • Most build systems, such as ant, provide direct support for running test suites as part of the application build process, and continuous integration systems, such as Cruise Control or Hudson, kick off such builds automatically each time code is committed to the team's version control system


Situation
Recently, I ran into project OpenSatNav. It's an open-source version of AndNav2, that is navigator application for Android OS based on OpenStreetMap. Great project, still pretty young, but dynamically expanding. I watched a few issues being fixed by the developers involved, and noticed that the process of findind a solution was a bit erratic. There were several attempts to guess a solution, and guesses were not perfect, but then there were a few better guesses.  Some NullPointException bugs cropped out after a few days and were fixed. Still, some issues were reported, but never reproduced, so by the token "it doesn't show the problem anymore, so let's close this issue", the issue has been closed. What was obvious to me, is that the solution is not necessarily correct. The testing was done manually and without even any systematic approach.

Spring into Action
It was obvious to me that what was definitely missing, was the automated testing, especially unit testing. I tried to step in and encourage unit testing. The idea of TDD, or any unit testing that I proposed several times was for the project team like a fairy tale about a bad wolf. But the developer team and the project lead were friendly and not exclusive.The lead-developer on this issue, responding to my requests, did include a well defined test-scenario with the fix code. I thought: it's not bad, I'll step in and write a unit or functional test for this fix. I have experience with TDD for Android, Java, GWT and Flex projects.

Result
It took me time (I have a full-time job and four children ages 4 - 19, plus, I took this as an opportunity to review the currently best practices for testing for Android OS), but finally I got to writing the test. And here's what I have found, which may be very well what also you experience is in this matter.  While writing a unit or a functional test for your own fix or new feature is a fun and a relatively straightforward activity, writing a test for a code written by someone else, is neither much fun nor simple. You end up reverse engineering the whole part of the system that surrounds the part where the fix was made.

Conclusion
Simple. Write your own tests. This, was for me always fun and an enlightening experience. And, I think, my design and coding have improved because of the tests I wrote. Tests for my own fixes.  Tests written immediately after I have written the code (CALTAL), or even just before I have written the code.

Resources
The following are useful for getting quickly to speed with TDD, esp. for Android OS development:

Thursday, September 3, 2009

Using FlexUnit to Unit Test Cairngorm Visual Objects

Introduction
In a RIA application a typical split of the source code (counted by code size, in bytes) is as follows:
  • 45-60% - client: visual objects like views and their sub-components with their logic
  • 15-20% - client: non-visual objects (primarily Cairngorm worker-to-service piping)
  • 30-35% - server: middle-tier code
In the couple medium-size business application, I have analyzed, the middle-tier was implemented in Java and the client was implemented in Flex using the Cairngorm architecture. So, I don't have verified numbers for other RIA configurations.

If we are determined to use TDD or simple just provide automated tests for our application and get the most coverage for the effort required to develop these tests, it seems we could use the following testing methodologies:
  • FlexUnit testing for the client, especially the client's visual objects
  • FlexMonkey tests for whole client's features
  • jUnit tests for the middle-tier code.
I another blog, I will touch on the FlexMonkey. In this one, I'd like to present how we can unit test the visual layer of the client using the FlexUnit framework. jUnit testing is well described in many other sources.

Testing Scenario
In the spirit of Cairngorm, a UI user gesture is directed to a handler which creates a Cairngorm message, attaches a payload to it (any relevant information) and dispatches it (event.dispatch()). Our test will mimic a user gesture (click a button) and will try to catch the dispatched Cairngorm event and verify its payload. We're using Flex 3 (ver. 3.2) and FlexUnit 4 beta 2.

Sample Application
To explain the topic, I'll be using the following sample application. The view (Main.mxml adds it to the ViewStack) is (to see the code in a new window, move your mouse pointer over the code and click the left of the icons that appear in upper-right corner):
<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml"
width="400" height="300">

<mx:Script source="MyViewScript.as" />

<mx:HBox verticalAlign="middle" >
<mx:Text id="txtValue" text="Entry:" />
<mx:TextInput id="entryTextInput" />
<mx:Button id="btnSave" label="Save" click="onBtnSaveClick(event)" />
</mx:HBox>

</mx:VBox>

The script used bu the view is:
import gov.olcc.fishbait.events.SaveEntryEvent;
import gov.olcc.fishbait.model.ViewModelLocator;
import gov.olcc.fishbait.vo.EntryVO;

public var modelLocator:ViewModelLocator = ViewModelLocator.getInstance();

public function onBtnSaveClick(event):void
{
trace("clickHandler detected an event of type: " + event.type);

var entryVO: EntryVO = new EntryVO();
entryVO.text = entryTextInput.text;

var saveEvent: SaveEntryEvent = new SaveEntryEvent(entryVO);

saveEvent.dispatch();
}


and the TestRunner class to run the test is
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns="*"
xmlns:flexunit="http://www.adobe.com/2009/flexUnitUIRunner"
xmlns:business="gov.olcc.fishbait.business.*"
xmlns:control="gov.olcc.fishbait.control.*"
xmlns:view="gov.olcc.fishbait.view.*"
layout="vertical"
width="100%" height="100%"
creationComplete="runTests()">

<mx:Script>
<![CDATA[
import com.adobe.cairngorm.control.FrontController;
// import gov.olcc.fishbait.view.TestFishBaitView;
import gov.olcc.fishbait.view.MyView;
import org.flexunit.runner.FlexUnitCore;
import org.flexunit.flexui.TestRunnerBase;
import gov.olcc.fishbait.view.MainTest;
// import gov.olcc.fishbait.view.TestFishBait;

//Add an import statement(s) for the class(es) under test
private var core: FlexUnitCore;

private function runTests():void
{
core = new FlexUnitCore();
core.addListener(testRunner);
core.run(MainTest);
}

]]>
</mx:Script>

<!-- Cairngorm Controller and Service Locator -->
<control:FishBaitController id="controller" />
<business:Services id="services" />

<flexunit:TestRunnerBase id="testRunner" width="100%" height="100%" />
</mx:Application>

The trick is to be able to catch the Cairngorm event. What is not obvious, the event.dispatch() method uses a CairngormEventDispatcher, so we need to add our listener to it. The resulting test code is
package gov.olcc.fishbait.view {
import com.adobe.cairngorm.control.CairngormEventDispatcher;
import flash.events.MouseEvent;
import gov.olcc.fishbait.events.SaveEntryEvent;
import gov.olcc.fishbait.model.ViewModelLocator;
import gov.olcc.fishbait.vo.EntryVO;
import mx.automation.codec.AssetPropertyCodec;
import org.flexunit.Assert;
import org.fluint.uiImpersonation.UIImpersonator;
import org.flexunit.async.Async;

public class MainTest {
var myView: MyView;
public var modelLocator:ViewModelLocator = ViewModelLocator.getInstance();

[Before(async,ui)]
public function setUp():void {
myView = new MyView();
UIImpersonator.addChild(myView);
}

[After(async,ui)]
public function tearDown():void {
UIImpersonator.removeChild( myView );
}   

[Test(async,timeout="3000")]
public function testOnBtnSaveClick():void {
CairngormEventDispatcher.getInstance().
addEventListener(SaveEntryEvent.SAVE_TEXT,
Async.asyncHandler( this, handleTestOnBtnSaveClick, 3000 ),
false,0,true);

myView.entryTextInput.text = "Test Text";
var clickEvent: MouseEvent = new MouseEvent(MouseEvent.CLICK);
myView.btnSave.dispatchEvent(clickEvent);
}

private function handleTestOnBtnSaveClick(event:SaveEntryEvent,
passThroughData:Object):void {
var entry:EntryVO = event.text;
Assert.assertEquals("Test Text", entry.text);
}
}
}

Other points about this test:
  • We use FlexUnit UIImpersonator as a parent to our view. Without adding a view to a parent, the UI controlls are not initialized and can't be used.
  • To get the instance of the CairngormEventDispatcher, we use its static mathod getInstance().
  • Since the actual test happens in the event handler, we need to user an annotation [Test(async,timeout="xxx ms"] to request the Async support for the test.
  • Then, instead of providing just the handler method as an argument to the assEventListener(), we wrap this method in Async.asyncHandler(), which will wait for the handler to be called unless the handler will not be called within specified time, in which case the test will fail.
And this is it. Enjoy testing Cairngorm visual objects.

Wednesday, May 20, 2009

Using Unit Testing to Test GWT RCP Calls

This is a short note. I'm working on a GWT application and ran into a problem with an RPC call which gets some objects from the database using Hibernate and passes them back to the client. I'm going to solve the problem using Dozer, but I needed to confirm this was the problem and simplify the testing of this in future. So, I decided I want to unit test this service from the client's perspective. Here are my notes from this exercise:
  • The easiest way to create a GWTTestCase is using the GWT's jUnitCreator. Creating it by hand is possible but tricky.
  • The asynchronous test needs to use delayTestFinish(delayMs) and finishTest(). In my case, I had to set 5000 Ms. For some reason, 500Ms, which I thought would be more than enough was timing out.
  • The good news is, that when using Eclipse plugin for GWT, starting initiating Run as JUnit Test on the GWTTestCase test starts for you also the server. And doing the same with Debug as JUnit Test allows to debug the client as well as server code.
Note: the similar test is supported in Flex application!