Skip to main content
Test-Driven Development and Continuous Integration for Mobile Applications

The Architecture Journal

by Munjal Budhabhatti

Summary: This article demonstrates how test-drivendevelopment and continuous integration addresses the unique challengesencountered when creating Windows Mobile applications.

Contents

Current State of MobileDevelopment: Issues and Challenges
Test-Driven Development
Unit testing
Continuous Integration
Source Code Repository
wMobinium.net
Faster Successful Builds
Benefits of Using CI
Conclusion
Resources
About the Author

Current State of Mobile Development: Issuesand Challenges

Globally, the number of mobile phone subscribers isapproximately 2.5 billion and is expected to grow to 4 billion by 2010. Themobile device is now a richer platform for application delivery due to such anexponential growth and wide spread usage. The critical factor, as always, isthe end user experience: application usability, reliability, and performance.

Complicating matters, the software development world is movingfrom weekly and monthly deployment cycles to continuous deployment. So how canone ensure that a user always has the best experience?

Many that have looked at the agile space will be familiarwith two of the core extreme programming practices: The driving of developmentwith automated tests, a style of development introduced by Kent Beck called test-drivendevelopment; and a software development practice of frequently integratingbuilds called continuous integration, as articulated by Matthew Foemmel andMartin Fowler.

These practices are not new to the software world. However, mobileapplication development has lagged in taking advantage of the test-drivendevelopment and continuous integration endowed by the enterprise softwarecommunity. This is partially a result of limited or unavailable mobile platformsupport in existing toolsets such as NUnit/MSTest or Cruisecontrol.net/TeamFoundation Server.

A few mobile testing tools allow recording user interactionsvia a graphical representation of the client device but do not provide granularcontrol over the tests. Other tools either demand scripting on a mobile deviceor expect tests to be executed, manually, on the device. As a result, mobileapplication testing is inefficient and complex, hindering productivity.

Test-Driven Development

Test-driven development (TDD) is an evolutionary approachwhere the development of code is driven by first writing an automated testcase, followed by writing the code to fulfill the test and then refactoring.

TDD essentially is test-first development + refactoring

Red/Green/Refactor—the TDD mantra—is an order to the task of

programming:

  1. Red: Write a small automated unit test that doesn’t pass, and perhaps doesn’t even compile at first. (See Figure 1.)
  2. Green: Write the code necessary to pass the failing test. Ensure other tests pass as well, if present, in the suite. Check-in the code in the source code repository. (See Figure 2.)
  3. Refactor: Making existing code beautiful, in small incremental steps, without changing the intent. (See Figure 3.)

Bb985498.jour14_Test-Driven_image001(en-us,MSDN.10).jpg
Figure 1. Sample test cases

Bb985498.jour14_Test-Driven_image002(en-us,MSDN.10).jpg
Figure 2. Sample code

Bb985498.jour14_Test-Driven_image003(en-us,MSDN.10).jpg
Figure 3. Sample refactoring

This technique is thus reverse to traditionalprogramming—developing code followed by writing a test, which is executedeither manually or automatically. Why embrace such a change, especially whenone might tend to think that it’s extra work? In reality, test-drivendevelopment is risk-averse programming, investing work in the near term toavoid failures (and even more work) in the late term—Kent Beck has called it “away of managing fear during programming.”

“Test-driven development is a way of managing fearduring programming—fear not in a bad way—but fear in the legitimate. If pain isnature’s way of saying ‘Stop! ’ then fear is nature’s way of saying ‘Becareful.’”—Kent Beck

The benefits of TDD

  • Design improvement. Writing a self-contained test case enforces the creation of decoupled code—not tightly integrated with other code—thereby increasing the cohesion of the code while decreasing the coupling.
  • Documentation. A well-written unit test case provides a working specification and communicates the intent of the code clearly. In addition, whenever the code changes, the unit test case must be updated to pass the test suite. Hence, a unit test case always stays in sync with the code naturally. This is unlike traditional unit test cases, developed with Microsoft PowerPoint or Microsoft Word. While such documents start off with good intentions, over time, the result often becomes out of sync with the underlying implementation.
  • Safe change in the system. TDD provides continuous feedback about whether the changes made in the code worked well with the other parts of the system.
  • Fail fast. Unit testing can isolate problems quickly, reducing debugging activities and allowing the system to fail fast.
  • Beautiful code. Beautiful code means code which expresses intent clearly, can afford changes to add features, and has no duplication. Refactoring retains the behavioral semantics of the code—functionality is neither added nor removed. It is about improving the code quality which brings business value.

Automated unit test execution is one of the vitalrequirements of TDD. However, because the testing tools are still evolving, theautomated execution is not currently viable in mobile application development.Implementing TDD in this environment is therefore quite challenging, if notimpossible.

Unit testing

Testing is customarily thought to be as a methodical processof proving the existence or lack of faults in a system. When a test case iswritten before writing the code, the test case becomes a specification, insteadof a mere verification of the feature.

Tests are also a way of documenting found defects.Let’s assume a defect was discovered in quality assurance while testing newlydeployed bits. Even if this defect was very trivial to fix, TDD demands a testcase. First, write a test case that simulates such a failing behavior, and thenwrite code to pass the test. Such a practice would ensure that defects, nomatter how petty, do not creep through the system and regression testingbecomes part of the test suite. Automated test execution locally, beforecommitting the changes to the Source Control Repository (SCR), would furtherreduce the broken builds phenomenon.

It is important to prepare the test environment on anemulator as close to the target hardware as possible. Developing and testing WindowsMobile applications on an x86 emulator makes little sense when targetinghardware exclusively for ARM architecture, an architecture dominant in lowpower consumption electronics. Furthermore, in the real world, components oftenhave dependencies on other objects, databases, or network connections. It isvery easy to fall into a trap of assuming that these dependencies work flawlessly.Hence if tests are written without taking dependencies into consideration, anincorrect feedback is possible for those tests which fail due to dependencyproblems.

One way to safeguard against dependencies is to build theobject graph or set up the database in a required state before executing thetest case. This would solve the issue but would increase test execution timeand build time.

A more elegant approach would be to instantiate test objectsand replace object dependency by implementing mocks or stubs—objects thatimitate the behavior of real objects. This ensures isolated test execution andhence reliable test results. Caution should be taken while faking the realobjects with mocks or stubs. It is probable that the entire unit test suiteexecutes faultlessly, yet the product might fail in quality assurance testing.I have found in my own experience that complementing mocks and stubs objectswith integration tests provides a true sense of confidence.

Continuous Integration

Martin Fowler has described continuous integration (CI) as asoftware development practice of frequently integrating builds, often multipletimes a day. A typical CI workflow, as shown in Figure 4, would be:

Developer:

  1. Writes a new unit test case.
  2. Executes the unit test case locally on the emulator and confirms that the test case is failing.
  3. Adds or modifies code to pass the test case.
  4. Executes the unit test case locally on the emulator and confirms that the test case is passing.
  5. Commits the code to the SCR.

CI Server:

  1. Downloads the source code whenever there is a change in the SCR.
  2. Compiles and inspects the source code, and creates new binaries.
  3. Sets up external dependencies such as database schemas, and resources (configuration files, satellite assemblies).
  4. Deploys the new binaries to and executes the tests on the emulator.
  5. Packages and deploys the product to staging environment.
  6. Generates feedback based on the results of the build.

Bb985498.jour14_Test-Driven_image004(en-us,MSDN.10).jpg
Figure 4. Continuous integration in .Net Windows Mobile application

Source Code Repository

All the essential files required to build a product residein the source code repository (SCR). It plays an important role in the softwaredevelopment life cycle and CI. SCR tools such as Subversion and Visual StudioTeam Foundation source control enable teams to work collaboratively—on the sameor different artefacts simultaneously, track code changes effortlessly, andwork on different versions of files concurrently.

The CI server obtains the latest source code from SCR,locates all required dependencies, and builds the product independently fromthe previous build output. SCR allows the team to be more productive—a new teammember does not need to reconfigure third-party libraries, project structures,or IDE settings for the project. Moreover, it reduces debugging time byallowing the team to remove the current changes which would be small andincremental if using TDD practices. The system could be safely reverted to aprevious version of the code.

It is vital to include all dependencies in the SCR: Thisincludes the Windows Mobile SDK, .Net Compact framework installer, VirtualMachine Network service drivers and other third-party components and utilities.

“Continuous integration is a software developmentpractice where members of a team integrate their work frequently—usually eachperson integrates at least daily—leading to multiple integrations per day. Eachintegration is verified by an automated build (including test) to detectintegration errors as quickly as possible. Many teams find that this approachleads to significantly reduced integration problems and allows a team todevelop cohesive software more rapidly.”—Martin Fowler

Automated build

Contradictory to some misconceptions, the automated build inmobile applications is much more than a simple code compilation. It assemblessource code from the SCR, compiles code to create binaries and dependencies (suchas configuration objects, resource assemblies, and so forth), inspects anddeploys compiled binaries to a mobile device or an emulator, loads databaseschemas, and executes tests remotely on the mobile device.

Build tools such as Nant and MSBuild do not support mobileapplication deployment, partially because mobile device support in these toolsis still immature. In addition, unit testing tools such as NUnit and MSTesthave a similar problem of executing tests remotely on a mobile device. To avoidthese limitations a new tool is essential.

wMobinium.net

To address these problems, I created a tool wMobinium.netwhich assists TDD and CI implementation in .Net mobile applications. wMobinium.netis a unit testing tool that supports automated deployment and automated remoteunit test execution. It has a Visual Studio add-in to support TDD in .Netmobile applications. It is a freely available tool on the CodePlex open sourceWebsite (see Resources).

Automated deployment

Unlike desktop application development, mobile applicationdevelopment faces unique challenges in deployment: first, a deployment isrequired for unit testing features on the device and second, deployment isnecessary after a successful build to deliver the working solution on a stagingenvironment for quality assurance testing.

For every build, the newly compiled binaries anddependencies must be copied to a program folder on a device. When anapplication entails testing on multiple devices, there will be addedcomplications to the deployment process. To circumvent these problems,wMobinium.net offers a deployment tool which implements Window CE’s RemoteApplication Programming Interface (RAPI), and facilitates file and folderdeployments. This relieves the pain of manual deployments.

Frequent commits

One of the key components for a successful CI implementationis frequent commits and hence frequent builds. With longer commit intervals,team members tend to work in isolation and the build is more prone tointegration issues. When a team member spends more time on a feature andencounters integration problems while committing the code, he tends to bereluctant to remove the changes and revert to a previous version of the code.This reluctance might increase the amount of time and resources spent on debuggingactivities. In an ideal scenario, team members check-in the code at intervalsof 30-60 minutes or less. The check-in duration could be extended by a fewhours, but should always be less than a day.

Faster Successful Builds

Once a developer commits code to the SCR, waiting for thefeedback from CI slows down the development process. Longer waits result indecreased productivity. Furthermore, some of the subprocesses of the build,such as deployment and testing, are executed on a device/emulator making theseprocesses inherently slower than it would have been on a desktop.

To reduce build times, concentrate on the weakest link—thecomponent that takes the longest time to execute. More often than not, thecause would be an external dependency, such as a database or other objects.Accessing a database and setting up test data for each test case is aresource-intensive operation. As I mentioned earlier, mocks or stubs, should dothe trick. If it is impractical to do so, move the test cases to secondary ornightly builds—scheduled builds that execute at night when most of theresources are idle. Test cases targeting tests scenarios on multiple devicesshould be added to secondary or nightly builds as well.

Failing builds cause the most frustration—as if the entirechain of software churning has been stopped. The code in the SCR is no morereliable and the team is blocked from getting the latest source code. The teamneeds to resolve the issue quickly by fixing the build. If a test case iscausing the failure and fixing the problem might require a longer duration, itis safe to ignore the test case temporarily to allow the build to succeed.However, it is vital to track these ignored test cases on an easily accessibleproject wall, a physical white board or a virtual board using collaborativesoftware. The ignored tests should be fixed at a later time and added back tothe test suite.

Automated unit testing

It is quite common to see that the same defects resurfaceafter a few builds and we often hear a quality assurance analyst say, “but thisdefect was already fixed in a previous build.” Boomerang defects reveal theimportance of writing a test for each encountered defect before modifying thecode base. Once the test case is fixed, the entire test suite must be executedand passed before checking in the modified code to the SCR.

I have been on a few projects where the team executes thetest suite manually on a mobile device. Imagine a mobile application developerwho spends few minutes changing the functionality, but spends double the timeto test it manually. This will not only discourage a developer but will alsoaffect productivity.

wMobinium.net resolves this annoyance by automating theentire unit testing workflow. Unlike traditional unit testing, wMobinium.netpresents the test case selection on the desktop, executes tests on the device,and displays results on the desktop. It takes care of some of the complicationssuch as the following:

Remote execution of test cases

In order to execute the test cases remotely on a mobiledevice/emulator, the tool serializes metadata information of the selected testcases, starts a conduit process and executes tests on the device. To provide correctreporting to the CI server, the remote process must be started synchronouslyand monitored continuously, which is quite a challenge.

Serializing test results to desktop

In the absence of support for remoting in the .Net CompactFramework version 2.0, the device must communicate with the desktop using sockets.The events must be serialized, sent to the desktop through a socket,deserialized, and propagated to the appropriate event listeners.

wMobinium.net add-in

The tools described here assist the CI server tocontinuously build, deploy, and test a .Net mobile application. It would beconvenient if the unit testing feature was supported as an integrated tool inVisual Studio.

wMobinium.net add-in, a Visual Studio add-in (Figure 5), isa part of the wMobinium.net toolset. After activating the add-in, all theavailable tests in the solution are displayed in the tool window. A typicalworkflow would be:

  1. wMobinium.net tool displays available test cases in a solution.
  2. User selects test cases to execute.
  3. Selected test cases are serialized and sent to the connected device/ emulator.
  4. Test cases are executed on the device/emulator and results are sent back to the desktop.
  5. Tool displays results on the desktop.

Bb985498.jour14_Test-Driven_image005(en-us,MSDN.10).jpg
Figure 5. wMobinium.net add-in

Benefits of Using CI

Stakeholders and project sponsors always favor reliableoutcomes, clear communication, project visibility, and superior quality ofsoftware. Software development, however, seldom offers such qualities withoutthe right processes and practices.

When everything seems to be going well, any defect mightsuddenly jeopardize the development schedule. Especially during “Big-bang”integrations, even small issues—like missing configuration entries, out-of-syncdatabase, or missing dependencies—could be extremely detrimental whenencountered together.

Continuous integration enables faster feedback. At everychange—adding new or modifying existing features, no matter how big orsmall—the CI server would integrate the new parts which would pass through theentire automatic build cycle—compilation, testing, inspection, and deployment.This provides visibility of the progress of the project, enhances the qualityof the software developed, and builds the morale of the team.

CI does not provide these functionalities out-of-the-box. Itis very possible to implement CI without including automated tests or inspectionin the builds process; however, such a setup would be the least beneficial.Many, including me, consider that CI without testing is not CI at all.

Conclusion

From a user perspective, TDD and CI implementation is thesame in a traditional desktop application as it is in a mobile application. Theuser creates a new failing automated test case, writes the code to pass thetest, and refactors the code without changing the intent. The CI server pollsfor the latest source code creates new binaries, executes the tests, andgenerates the feedback. However, in a mobile application the implementationdiffers in the remote execution of test cases, notification of test results,and build deployments. These complexities are handled by the wMobinium tool.

In my past experience at one of the biggest microfinanceorganizations in Africa, my team and I developed a .Net mobile application. Inthe absence of supporting tools, the development implementing TDD and CI,although arduous, improved overall application design, reliability, andperformance.

With the release of .Net Compact Framework version 2.0, theperformance of .Net mobile applications has improved radically. The newerversion provides improved developer productivity, greater compatibility withthe full .Net framework, and increased support for device debugging. Combining.Net Compact Framework with TDD and CI (using wMobinium.net) would bringgreater benefits to an organization and take the mobile application platform tothe next level.

With the proliferation of new mobile devices today, themobile application is becoming a crucial part of a broader enterprise productoffering. It is pragmatic, more than ever, to bring mobile applicationdevelopment out from isolation and include it in enterprise-wide test-drivendevelopment and continuous integration efforts.

Resources

About the Author

Munjal Budhabhatti is a senior solution developer atThoughtWorks. He possesses over 10 years of experience in designing large-scaleenterprise applications and has implemented innovative solutions for some ofthe largest microfinance, insurance and financial organizations in Africa,Asia, Europe, and North America. He spends most of his time writingwell-designed enterprise applications using agile processes.

 

This article was published in the Architecture Journal, a printand online publication produced by Microsoft. For more articles from thispublication, please visit the Architecture Journal Web site.