Showing posts with label tdd. Show all posts
Showing posts with label tdd. Show all posts

Monday, March 18, 2019

jUnit Fun

jUnit and Mockito Fun

More Interesting Elements of Unit Testing and Mocking


  • Verify that a method was called on a mock

    • Verify the parameters the method was called with
  • Return a custom response from a method called on a mock, response based on the parameters of the call
    Mockito.when(myMock.save(any(Person.class))).thenAnswer(i -> {
        Person person = (MyClass) i.getArguments()[0];
        return "Hello, " + person.getFirstName();
    });

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.

Tuesday, August 18, 2009

Using FlexUnit 4 with Flex 3: Sample Application

Introduction
We had hard time finding on the internet a sample like this. So, here's ours. Additional steps required for this test to be run:
  • download FlexUnit 4 from their site.
  • add the FlexUnit swc files to the project's classpath
  • copy the sources below into your project and adapt them (use the view source icon in each source code frame below to view/copy the source code).
  • once everything is on place, right click on the TestRunner and select Run Flex Application.
At the end of the article, we have added some notes about using FlexUnit with FlashBuilder 4 and Flex 4
Enjoy! It's a great tool!

File structure

Tested Object

package olcc.account
{
public class Account
{
public function Account(){
}

private var balance:Number=0;

public function deposit(amount:Number): void {
balance=balance+amount;
}

public function withdraw(amount:Number): void {
balance=balance-amount;
}

public function getBalance():Number {
return balance;
}
}
}
Test Suite (Optional)

package olcc.account
{
import org.flexunit.runners.Suite;

[Suite]
[RunWith("org.flexunit.runners.Suite")]
public class MyTestSuite
{
public var t1: AccountTest;

}
}


Unit Test

package olcc.account
{
import org.flexunit.Assert;

public class AccountTest
{
[Test]
public function testNew():void {
var account:Account = new Account();
Assert.assertEquals("Expecting zero account balance", 0, account.getBalance());
}

[Test]
public function testDeposit():void {
var account:Account=new Account();
account.deposit(50);
Assert.assertEquals("Balance on a new account after 50 deposit is 50",50,account.getBalance());
account.deposit(25);
Assert.assertEquals("Balance after 50 deposit and another 25 deposit is 75", 75,account.getBalance());

}

[Test]
public function testWithdraw():void {
var account:Account = new Account();
account.deposit(100);
account.withdraw(50);
Assert.assertEquals("Balance should be: + $100 - $50 = $50",50,account.getBalance());
}
}
}


Test Runner
<?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"
creationComplete="onCreationComplete()">

<mx:Script>
<![CDATA[
import org.flexunit.runner.FlexUnitCore;
import org.flexunit.flexui.TestRunnerBase;
//Add an import statement(s) for the class(es) under test
import olcc.account.MyTestSuite;

private var core: FlexUnitCore;

private function onCreationComplete():void
{
core = new FlexUnitCore();
core.addListener(testRunner);
core.run(MyTestSuite);
}
]]>
</mx:Script>

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

Using FlexUnit 4 with Flex 4

Flex 4 beta2 has support for FlexUnit, and the most recent version of it which is version 4.0. If you go to the New->TestCase menu, FlashBuilder can create for you a whole test class. And add to the flex build path the necessary libraries. This is done pretty well. But when I tried to apply the simple test application presented above to a Flex 4 application, I ran into multiple problems. One critical, as of today, was the issue that the AsDoc for Flex 4 is not available, nor much of the documentation for it. So, some classes from FlexUnit 4 that I needed (like TestRunnerBase), I wasn't able to find. Until these issues are resolved in Flex 4, I decided to use the FlexUnit 4 directly. To do this, I removed the Flex 4 libraries from the build path and added the FlexUnit 4 beta 2 libraries (.swc files). In general, the flex parser is not always stable, which showed up in this exercise and I had a compilation error that shows every other time I compile my TestRunner.mxml (with the same source code), but I can run the tests. Simply, I made sure that the last compilation is a clean one. Also, closing and reopening the project eliminated this issue.

Tuesday, August 11, 2009

FlexUnit Plugin for Eclipse

Since we intend to do unit testing in our Flex+Java development, I have been playing with FlexUnit and have found an eclipse plugin that makes it easier to use (also, in plugin central). Here's a summary and lessons learned on how to start with the plugin

Installation
Follow the installation instructions from here. Once installed, open the plugin's help in Eclipse and configure it. A few points:
  • Download FlexUnit and FlexUnit extension for the plugin.
  • You will need to have Flex Builder 3.
  • You will need a debugger version of Flash Player (I used version 10). A standalone player used by the plugin comes with Flex Builder (directory: player)
  • Follows instructions from Adobe on how to enable logging and error output for Flash Player. When you follow them, after you create a mm.cfg file, you will need to restart all instances of Flash Player for the Logs folder to show up.
Using The Plugin
To use a plugin:
  • Create a unit test using Flex Builder's wizard. I recommend keeping them in another source folder, so they can be easily skipped when releasing the app. For example, keep the flex source in flex-src and flex tests in flex-test. The server code put in java-src and java-test, or whatever language you use for the middle-tier.
  • Create a harness. Right click in the test file in the project navigator, find FlexUnit menu and select Create Harness. This will create a small mxml file for your test. However, if you use FlexUnit 0.9, the code needs a correction. Replace:
    EclipsePluginTestRunner.runTests( new Array(AccountTest.suite()) );
    with
    EclipsePluginTestRunner.run( AccountTest.suite() );
  • Run the test. Right click on the harness file and select Run from the FlexUnit menu. Observer the test results on the nice eclipse viewer.
I had the problem that the test launch process never finishes in eclipse. But it doesn't seem to be harmful. Just ignore it.

Summary
It's a great plugin. It could do quite a bit more, but it's a great start. It worked for me with a FlexUnit 4, when I used the syntax of FlexUnit 0.9. When I switched to FlexUnit 4 syntax, I didn't have to apply the correction mentioned above to the auto-generated harness to compile. However, I didn't get my tests executed. So, I guess, for now, using the FlexUnit 0.9 is a better option. However, I have heard from the plugin author that he intends to do another release of the plugin.