CALL +44 (0)20 7183 3893
agile, geeky, and eccentric Dev Blog

Thursday, April 4, 2013

An efficient implementation of Agile development for Force.com


An efficient implementation of Agile development for Force.com


We have been developing on the Force.com platform for nearly two years using the Agile software development methodology. We sometimes work simultaneously on different Force.com projects in our daily work.

Over time we have gained a lot of useful experience in developing for the Force.com platform using the Agile methodology. We have gained that experience by contributing to and delivering a large Enterprise application that runs on the Force.com platform as well as several smaller internal projects.

It will be assumed that you are familiar with the Agile development methodology and the concept of continuous delivery of useable software throughout the product development lifecycle.

We are constantly striving to automate as much of the continuous integration process with Force.com projects as possible. The Force.com platform provides unique challenges to creating a full continuous integration setup.

This article will describe some of the tools, methods and ideas that we use to make developing for Force.com as efficient and enjoyable as possible. More information on the tools and technologies that will be mentioned in this article can be found using the following links:

Summary of tools and technologies used




Development environment setup

Here are some useful tips on setting up a development environment so that you can begin writing code and for deploying already-written code.

Acquisition of a clean development environment (or org/organisation from now on)

Acquiring a clean development org is not currently automatable, but is nevertheless very easy and is not a frequent operation in usual circumstances: http://www.developerforce.com/events/regular/registration.php

Org naming convention

If you’re regularly switching between orgs or logging into the orgs of other developers on your team, it is very helpful to have a simple naming convention for the different orgs. It is especially convenient to use as few characters as possible to distinguish each Developer Edition account. This speeds up tremendously the process of switching between orgs, either when you're logging in through the browser or setting up an Eclipse Force.com project.

Easy switching between Salesforce orgs with Google Chrome

There is a very useful extension for Google Chrome called Force.com Logins (see above for download and installation). This allows one to rapidly switch between different Salesforce orgs, which is a pretty regular need for most Salesforce users/developers.

‘Tearing down’ a Salesforce org

Since it is not possible to ‘tear down’ a Salesforce org, it is necessary to be able to ‘clean’ it instead before deploying other code. The Salesforce Migration Tool can be used to 'undeploy' meta-data from a Salesforce org - this action is where the Migration Tool comes in most useful as developers regularly want to reload the latest version or a different branch of code from a source repository into their environment.

Performing the ‘undeployment’ action using the Salesforce Migration Tool is pretty laborious - it requires the creation of a (using the default name from the available sample) destructiveChanges.xml file listing all of the components that you want to remove from the org. You also must know what is in the org in order to remove it - therefore you must ‘retrieve’ the components you want to remove beforehand and use a script to generate the destructiveChanges.xml file from the directory of retrieved components. The components to retrieve are specified by means of a ‘package.xml’ file, similar to the one for undeployment.

The above detailed cleaning steps can all be forgotten about when wrapped with a good script, which should in principle do the following:

  1. The Salesforce Migration Tool is used to retrieve from the Salesforce org (whose credentials would be specified in the build.properties file) all of the metadata components that are declared in the package.xml file in the directory of the Salesforce Migration Tool. This is done by executing ant retrieveCode.
  2. A script is used to generate a destructiveChanges.xml file that contains an explicit list (i.e. no wildcard characters) of all of the components of each type retrieved from the Salesforce org. The destructiveChanges.xml file follows the schema convention used in package.xml.
  3. The 'undeploy' operation (ant undeployCode) is used to remove the metadata components listed in destructiveChanges.xml from the Salesforce org.
  4. New code is downloaded from a source repository (e.g. GitHub) and source branch specified by the user and deployed into the Salesforce developer org (e.g. git clone -b <repository URL> <branch name> followed by ant deployCode).


Writing the code

Here are some tips and experiences on ways to accomplish the production of good quality Apex code in a time-efficient manner.

Source version control and branching

We use Git, hosted on Bitbucket, for source version control. We also use the following very useful source branching model: http://nvie.com/posts/a-successful-git-branching-model

We use Gitflow to implement the above branching model. We highly recommend Gitflow for saving a lot of finger-aching Git commands.

Eclipse and the Force.com IDE for Force.com development

The Eclipse Force.com IDE is currently the only IDE integrated with Salesforce for Force.com development. The Force.com IDE is also available as an Eclipse plugin. A developer can choose to develop either ‘online’ or ‘offline’ with the Force.com IDE.

Online vs. offline Force.com development


Online
Offline
Saving any change requires request/response interaction with Salesforce server
Saving a change is instant but is only saved locally and is not synced to the Salesforce environment.
Constant feedback on your code's compilation status, helping to ensure that the code is always in a good or working state.
Feedback given one error at a time when saving bulk changes later, leading to lengthy and frustrating bouts of code fixes.
Constant backing-up of your code on your Salesforce environment
Only copy is on your machine until you push to your distributed source repository (or similar)
Must use Force.com IDE for file editing
Free choice of method for editing files

Online or Offline development?

Amongst us, we have tried both of these methods with similar experiences. We find that the two result in similar productivity but that we prefer the ‘online’ method. The main reasons for preferring online over offline are that it is less stressful to fix compilation errors as they come up (rather than face an onslaught later) and that it is a safer way of working - since the latest version of your code is always in Salesforce as well as on your machine.


Deploying Apex code into a managed package

Managed packages are always created and always reside in Developer Edition environments - hence ‘packaging org’. Here are some tips for keeping a managed package in a consistent and correct state.

Maintaining a packaging org

Creation of a managed package involves creation of a ‘namespace prefix’ which is unique to that package and all versions of it. The managed package is also tied to the Developer Edition environment that it is created in. Thus for a given managed package, the final build will always be completed within the same environment.

Ideally, each release of an application is created in a clean development environment to ensure that there are no 'old' components of your project still sitting in there. Since that is not possible due to the details mentioned above, it is important to be careful and vigilant to ensure that the contents of the package are always consistent with what is on the release branch of your branching model.

Once package components (such as Apex classes, Visualforce pages) become managed, there can be problems with repeatedly deleting and re-deploying them into a developer environment. For example: attempting to re-deploy managed classes that have been previously deleted using the Salesforce Migration Tool can give the error: "Entity is deleted".

This can only be fixed by going to Your Name -> Setup -> Create -> Packages -> <package name> -> Deleted Components and manually clicking 'Undelete' for each one.

Due to the regular occurrence of this issue, you should only make ‘deploy' operations using the Salesforce Migration Tool on your packaging organisation and manually remove components like classes that are no longer used.

This means that you need a way to ensure that the code in your packaging org is the same as the code in your source repository. It is easy to do this using the Force.com IDE and Git:

  1. Pull the latest code from your Github repo.
  2. Create a Force.com project in Eclipse using the directory of the code just pulled.
  3. Right-click on your project folder in Eclipse, then Force.com -> Refresh From Server. Providing your package.xml is set up to download the components that you want to update.
  4. Run 'git status' in the project directory to reveal any changes made to your code by the ‘Refresh From Server’ operation above. You will see any changes that were downloaded from Salesforce.

Final comment

Hopefully some of the above ideas and solutions will provide assistance and value to other developers out there who may be beginning to develop for the Force.com platform. For more experienced developers I hope that this article may provide ideas for improving their development workflow.

Wednesday, January 16, 2013

How To Test For CreatedDate and LastModifiedDate in Salesforce.com APEX

Introduction

Quite often you need to test a piece of functionality that processes date fields in Salesforce.com. Every object in Salesforce.com has system fields - CreatedDate and LastModifiedDate - which signify when a record was created, and when it has been updated the last time.

A Few Possible Approaches

Imagine, you are writing a test for a method that must return the most recently created Account. How would you do that? Unfortunately, Force.com does not allow programmatic modification of such system fields. So, the following code snippet simply will not work:

You may try to insert two records one after another, but they will all have the same CreatedDate, thus this approach will not work either.

One might decide to put an artificial delay into the code, so that records are guaranteed to be inserted at different times.


This approach is pretty hackish. First of all, Force.com does not have any sleep function that means you have to simulate it. Secondly, this can easily result into the 'Too many script statements' exception. Finally, unit tests should not depend on such time-based constructs. 

There can be another temptation of preparing a test environment by manually inserting records which will be later on used by a test. This is hardly an optimal approach either, as it makes a test expect a system to be in a known state, which makes it very brittle.

Test.loadDate() To The Rescue

Fortunately, Salesforce.com Winter '13 introduces a method called Test.loadData(). The method loads test data from a Static Resource, which can be just a CSV file. What is important for us, it allows setting System Fields, such as CreatedDate, and LastModifiedData, but not SystemModstamp.

So, the resulting test code will look like this:



Given that we have a Static Resource similar to the one below:


Static Resources

A static resource can be easily created in the Develop Section ([Your Name] -> Setup -> Develop -> Static Resources). Then, you can download it by using the Force.Com IDE or any other tool. Alternatively, you can manually create it locally in the 'staticresources' directory of your project, and deploy it to your Salesforce.com organisation. You will have to create both a resource file and a meta file.

In case, you wonder how Static Resources are different from manual insertion of records into a Salesforce.com organisation, there are a few points. First of all, it is for a test to insert data by calling Test.loadDate(), so a developer has control over it. Secondly, unlike some pre-loaded data, Static Resources can be distributed and put into your Source Control Management system. 

One Important Remark

A value of the CreatedDate must be always in past.

What About LastModifiedDate?

If you want to test a method that deals with the LastModifiedDate you can use a similar approach. However, your static resource must contain both CreatedDate, and LastModifiedDate. Otherwise, there will be an exception thrown saying that a LastModifiedDate cannot be earlier than a CreatedDate. Indeed, if you do not specify a value of CreatedData, Salesforce.com will use a date at the time of record insertion.

Be Careful With Custom Fields And Managed Packages

When a custom field is a part of a Managed Package its name is prepended with a package namespace prefix. It is done automatically by the platform, so typically a developer does not have to care about that. However, when you are inserting data by calling Test.loadData(), you have to prefix field names manually.

This may cause a bit of inconvenience, when you are developing code in one Salesforce.com organisation, where such code is not a part of any package, and have another organisation for building a package. You can solve this problem by using two branches in your Source Code Management system, such that one branch is used for keeping code which is in development, while the other one is used for code which is released in a managed package.

Source Code

You can file all the source code in the my Github repository.

Mike Borozdin, Software Developer
email:  mike.borozdin at cloudreach

Wednesday, August 22, 2012

Asynchronous Code Reviews as an Efficient Way of Ensuring Code Quality


Mike Borozdin (mike.borozdin at cloudreach)



The code review is a convenient way to ensure that code adheres to high quality standards. Code reviews provide a number of benefits. First of all, they help to make sure that every piece of code complies with company's/team's standards. 'Standards' should not be read only as guidelines for naming variables and code formatting, instead they may include such things, as design patterns and various approaches for writing code for a specific domain, language or a framework.

Secondly, a code review session can unearth potential problems with code and mitigate them at the early stages of a product life cycle.

Another interesting aspect of having code reviews is that they help to spread knowledge about an entire code base. Indeed, not every developer is given a chance to work on every part of a product and sometimes developers might have limited knowledge about parts of application that have not been written by them. Performing a code review provides such an opportunity and fosters having a better overview of the whole code base.

Finally, code reviews bring a great learning value and help us to become better developers. Often, a code review can trigger a good piece of advice from a peer.

In spite of the aforementioned benefits, code reviews are known to be time consuming and more importantly irregular events. However, these drawbacks can be avoided when performing asynchronous code reviews. The idea is inspired by the way GitHub works.

An asynchronous code review does not require the whole development team to be present at the same time in the same place. It only requires one other developer who can have a look at a piece of code, when they have a minute.

Furthermore, it is possible to make such a process mandatory and have every bit of code reviewed. This is also inspired by Github and the way many open-source projects accept contribution via pull requests.

No matter which source control management system (SCM) is used there is typically one main development branch and multiple features branches. Usually, a developer when finishing a feature would merge it into the main development branch. However, when doing asynchronous code reviews, a developer would not merge it, instead they would push it to a remote branch on GitHub and create a pull request.

Then, another developer would review code and leave their comments. The first developer would read the comments, introduce necessary changes and push it back to GitHub. The process continues until the reviewer is satisfied with submitted code.

Please note, that even though we give examples related to Git and GitHub, we believe it is possible to have asynchronous code reviews with any other SCM. After all, is is more about an efficient process, than underlying technology.

Wednesday, July 4, 2012

Inserting Contacts Programatically On Any Android Device*

Often, it is necessary to insert contacts programatically on Android devices. The documentation and tutorials provide information on how to do that. Unfortunately, inserting contacts on some devices, specifically the ones produced by Samsung, is not very straightforward. In particular, this problem has been spotted on Samsung devices running Android OS 2.2, 2.3.8, and 3.1.

The documentation suggests that an inserted contact must contain two compulsory system level fields ACCOUNT_TYPE and ACCOUNT_NAME. It is written in the documentation that the value of ACCOUNT_TYPE must contain your domain, while the value of ACCOUNT_NAME is supposed to carry the name of a user account using the domain.

Thus, one would write something like:

ArrayList insert = new ArrayList();

int rawContactInsertIndex = 0;

insert.add(ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
        .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED)
        .withValue(RawContacts.ACCOUNT_TYPE, "com.yourcompany.yourapplication")
        .withValue(RawContacts.ACCOUNT_NAME, "com.yourcompany.yourapplication.contact1").build());

insert.add(ContentProviderOperation.newInsert(android.provider.ContactsContract.Data.CONTENT_URI)
        .withValueBackReference(Data.RAW_CONTACT_ID, rawContactInsertIndex)
        .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE).withValue(StructuredName.GIVEN_NAME, "John")
        .withValue(StructuredName.FAMILY_NAME, "Doe").build());

try {
    getContentResolver().applyBatch(ContactsContract.AUTHORITY, insert);
}
catch (RemoteException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}
catch (OperationApplicationException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

The code will execute without any exception, however if you navigate to the Contacts application on a device, you will be surprised not to find a newly inserted contact.

It can take a quite a lot of time to understand what is going on. However, if you try to print out ACCOUNT_TYPE's and ACCOUNT_NAME of already existing contacts on a device with the following code snippet:
ScrollView scrollView = new ScrollView(this);
TextView contactsTextView = new TextView(this);

scrollView.addView(contactsTextView);

Cursor rawContactCursor = getContentResolver().query(RawContacts.CONTENT_URI,
        new String[] { RawContacts.ACCOUNT_TYPE, RawContacts.ACCOUNT_NAME }, null, null, null);

StringBuilder contacts = new StringBuilder();

while (rawContactCursor.moveToNext()) {
    contacts.append(rawContactCursor.getString(rawContactCursor.getColumnIndex(RawContacts.ACCOUNT_TYPE)) + "|"
            + rawContactCursor.getString(rawContactCursor.getColumnIndex(RawContacts.ACCOUNT_NAME)) + "\n");
}

contactsTextView.setText(contacts);

setContentView(scrollView);

You may notice that many contacts have an ACCOUNT_TYPE of 'com.google', while ACCOUNT_NAME contains your Google log-in name. Additionally, you may spot presence of contacts whose ACCOUNT_TYPE and ACCOUNT_NAME is 'vnd.sec.contact.phone'.

Such an ACCOUNT_TYPE corresponds to contacts created on a device having no synchronisation with Google or any other online services. Additionally, it is possible to use 'null' for both ACCOUNT_TYPE and ACCOUNT_NAME. In this case, contacts will be also displayed.

Thus, if you rewrite the code snippet given in the beginning of the article with that new value, your contacts will be displayed on a device.
ArrayList insert = new ArrayList();

int rawContactInsertIndex = 0;

insert.add(ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
        .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED)
        .withValue(RawContacts.ACCOUNT_TYPE, null)
        .withValue(RawContacts.ACCOUNT_NAME, null).build());

insert.add(ContentProviderOperation.newInsert(android.provider.ContactsContract.Data.CONTENT_URI)
        .withValueBackReference(Data.RAW_CONTACT_ID, rawContactInsertIndex)
        .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE).withValue(StructuredName.GIVEN_NAME, "John")
        .withValue(StructuredName.FAMILY_NAME, "Doe").build());

try {
    getContentResolver().applyBatch(ContactsContract.AUTHORITY, insert);
}
catch (RemoteException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}
catch (OperationApplicationException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

* Please note, we are speaking about Android devices with an operating system of verion 2.0 at least.

Wednesday, May 23, 2012

What I Do: Agile Architect

Software is complicated. You just won’t believe how vastly, hugely, mind-bogglingly complicated it is. Software is probably one of the most challenging and complex things our fair species has ever created. Unsurprisingly, this makes software difficult to produce at all, and incredibly hard to do well.

The process of making software — which we, lovingly, call software engineering — is mostly about managing that complexity. This is done so that humans can cope with it, harness it and do awesome things using it. One of the techniques used to contain complexity is abstraction. Software resembles a Russian doll of abstractions. Each layer brings us an increasingly human viewpoint that gets us closer to the problem domain. If the abstractions are good ones, we can write code in the terms our users can understand. If they are bad, then the Russian doll will resemble a scene from a Cronenberg film.

As an agile architect, my main role on projects is a steering and advisory one. I help guide the software towards good abstractions that contain the complexity. This allows us to deliver high quality code reliably and efficiently. Unlike a traditional software architect, I don't develop huge upfront designs that quickly become dangerously out of date. Instead, I work day-to-day as part of the team; keeping the big picture of the project’s in mind so our talented developers can focus on the functionality they're currently building. This high-level view allows me to step in when needed and offer guidance on how to solve particular problems. It also makes sure our solutions are cohesive, maintainable and flexible.

A lot of what I do is connecting from the business to the technical worlds, taking stories and fitting them into our solution’s jigsaw by translating complex requirements into tangible technical tasks. Working together, our developers and I ensure that the solution we’re developing is the right solution.

I'm usually involved right from the start of a project, building up a deep understanding of what the customer wants to achieve and the constraints they have. I will produce an initial high-level architecture that provides a scaffold from which the system will grow. That initial picture is likely to change as the software develops, but it helps our teams focus their thoughts on developing a great solution user story by user story by protecting them from much of the complexity.

I also have oversight responsibilities across our projects. I encourage our engineers to follow best practices, both technically and procedurally, and assist with organisational learning. I am responsible for validating solutions to keep technical risks to a minimum and with spotting useful patterns in what we develop.

The role of agile architect is an exciting and challenging one that keeps me learning. Every day, I am presented with new puzzles to solve, and the work is incredibly varied. One day the task at hand could be designing a distributed task system and the next I could be working on a line-of-business tablet application with a clever backend. This job gives me the rare privilege of working on some of the most cutting-edge aspects of cloud computing whilst getting to help some of the biggest brands in the UK solve their business problems.

Monday, May 21, 2012

Delivering Enterprise Android Applications Continuously


Siddhu Warrier (siddhu.warrier at cloudreach) 

Continuous Delivery (CD) makes sense on so many levels that I’m not even going try to restate its benefits. There have also been reams written on achieving continuous delivery when you’re in the business of developing, say, web apps. However, there is far less on the continuous delivery of private enterprise Android applications. 

It’s been a while since Cloudreach first got into the business of developing enterprise Android applications that interact with several cloud platforms. When we got started, there was very little by way of support for continuous deployment of Android applications that could not use the Android marketplace. 

Thankfully, though, the last couple of years have seen both the Android platform* and our development processes at Cloudreach mature significantly, as a result of which we have now introduced CD into our agile development process for mobile applications.

1. Wanted: Acceptance Testing framework for Android
We are currently working on a mobile and web application for a major manufacturer. At the very outset, we were very keen to implement CD. But we found that the biggest hurdle that we faced was the absence of an acceptance testing framework like Cucumber. 

It was then that we realised that the lovely folk at www.lesspainful.com decided to open-source Calabash (https://github.com/calabash), an acceptance testing framework for Android that brings Robotium (www.robotium.org) and Cucumber (http://cukes.info/) together. 

And before you could say ‘So that I can write automated acceptance tests’, we had our automated acceptance tests beavering away on our device!

2. Wanted: Private App Deployment and Crash Management System
The second challenge we faced was finding a private Android marketplace and crash reporting solution that was stable, and allowed for in-app upgrades. 

After looking at a fair few, we zeroed in on Hockey App (http://www.hockeyapp.net) because:
  • It provides a RESTful API that allowed us to automate deployments from our CI server.
  • It is cheap at $10 a month for an indie license.
  • It has a reasonably clean SDK
  • It didn’t do anything daft like write crash reports into a spreadsheet that quickly became un-openable.
However, there are a few things I didn’t quite like about HockeyApp. 
  • Why is the SDK an APKlib, and not a JAR? APKlibs are a great idea, but the Eclipse ADT’s support for it isn’t quite there yet.
  • Why is HockeyApp initialised in the application’s “main” activity? This seems to me rather brittle, and not as nice as ACRA’s approach.

3. Wanted: Artifact Deployment Solution
This was the piece of our CD jigsaw that we’d put together first (well before we started thinking of implementing CD). 

We use Maven and artifactory (http://www.artifactoryonline.com) for all of our Java projects, and the Maven Android Plugin (http://code.google.com/p/maven-android-plugin/) fit the bill very well indeed. It also allowed us to structure our Android project in a manner that was consistent with how we did the rest of our Java development.


4. Wanted: A sensible Git branching solution
As we have had occasion to mention previously on this blog, we’re wedded to Git and Github in a loving, stable, and monogamous relationship. We also found the Git Flow branching structure ideal for what we were looking to do.

Putting it all together

We are currently working on fortnightly sprints (we’re evaluating an alternative project management approach which is quite unlike a dime bar on one of our internal projects, but more on that in another post). 

During the course of a sprint, 
  • Every time one of our developers picks a story, he branches from the head of the develop branch to work on it. Once we’re done and the code has been asynchronously reviewed (more on that in another post), we merge the code back into develop, which triggers a build on our Jenkins CI.
  • At the end of the sprint demo, we roll our latest build on develop into the master branch using Git Flow. This triggers our CI, which then runs the full suite of automated tests and sends the aligned bundle to our artifactory repository and to HockeyApp. 
  • In a matter of minutes, our testers and early adopters receive an in-app notification suggesting that they upgrade.
The whole process has cut our deployment cycles down from half an hour or more to approximately 5 minutes of manual effort.

Areas for improvement

There’s a few things still holding us back. These include:
  • The Jenkins Android Emulator plugin has an annoying propensity for wiping the user’s data. This is a particular problem for us, as our app requires the presence of Google accounts on the device. We currently make up for it by triggering acceptance tests on real devices, but this is clearly not ideal.
  • HockeyApp does not allow us to have multiple applications with the same package identifier. This has therefore precluded our efforts to deploy every time we push to the develop branch. While we could work around this manually, this seems like rather an error-prone approach to take, as a result of which we’re still hunting for a better solution.
  • We have had issues with the Emma code coverage plugin and the production version of the Android Maven Plugin.
    In any case, the absence of branch coverage on Emma make it a non-starter in the first place.







Behaviour-Driven Development in .NET with SpecFlow and White

Mike Borozdin (mike.borozdin at cloudreach)


Introduction


This article gives a general overview of behaviour-driven development (BDD), talks about .NET tools for BDD (SpecFlow) and UI testing (White) and proceeds with a working example giving hands on BDD in .NET.

Behaviour-Driven Development (BDD) and Outside-in Development 


Behaviour-Driven Development (BDD) is a philosophy of software development where the focus, as the name suggests, is on implementing behaviour. First proposed by Dan North, this approach to development does away with a lot of the confusion — exemplified by questions like 'What do I test?', 'Where do I start testing?', and 'Where do I stop testing?' — that developers who set out to use TDD are faced with.

Outside-in development is a complementary technique that requires developers to focus primarily on defining customer requirements expressed as acceptance criteria, and work inwards towards building an implementation from there. BDD facilitates outside-in development by requiring the description of acceptance criteria as desired behaviours.

Let's take a look at a quick example. Consider the following user requirement:
As a user of this awesome application
I want to log in using my authentication credentials
So that not every Tom, Dick, and Harry can look at my precious data

One of the acceptance criteria for this story would be:
Given I am on the / page of the web application
When I enter my (awesome) authentication credentials
Then I should be presented with the home page

This criterion, written in plain English, describes the desired behaviour. This acts as an ideal starting point for us to write our acceptance tests. Once the acceptance tests have been written, a developer may then move inwards, writing integration and unit tests for the implementation that is required. It is important to note here that BDD does not end with the acceptance tests, but should be used throughout as we move inwards (see how Dan North suggests using shouldExhibitBehaviour(...) to describe tests rather than testExpectedFunctionality(...)).

Next, we show how to implement the outermost step of the BDD process in a .NET project. To do this, we use SpecFlow, a tool that allows you to translate acceptance criteria written in plain English into executable tests.

SpecFlow


SpecFlow translates human-language acceptance tests into runnable .NET code. What is even more interesting is that it is capable of generating test reports that can be understood by non-technical stakeholders like business analysts.

Acceptance tests (sometimes called scenarios in the literature) are specified in Gherkin, a plain text DSL that adds some semantics to plain English. An acceptance test describes a sequence of events in the form: Given [pre-condition], when [action], then [effect], when [another action], then [another effect], and so on. For example,

Given I am in the New Customer Form
When I leave the company name field blank
Then I should be presented with an error saying so
Here's a more complex example with multiple actions:
Given I am in the Login Form
When I enter a valid e-mail in the e-mail field
When I enter a valid password in the password field
Then I should see the Dashboard window

Testing Desktop UIs with White


As an acceptance test describes behaviours that are visible to the end-user, they typically require a means of instrumenting interactions with the application's UI; this allows you to automate actions like clicking on buttons, filling in text fields, and searching for displayed text.

In this post, we describe the use of White, a UI testing tool that allows you to automate interactions with desktop applications written in .NET (WPF and WinForms), as well as native Windows applications.

Working Example


Let's use SpecFlow and White to write a simple desktop application. 

Stories and Acceptance Criteria


The example application we shall look at in this post is a simple app that takes a customer's details and saves it to a database.

To start us off, our business analyst has provided us with this story,

Feature: Saving Customer Information

As a sales manager
I want to save a customer’s details
So that I can contact them later

and these acceptance criteria.

Scenario: HappyPath

Given I am in the New Customer window
When I enter a company name in the company name field
When I enter a contact e-mail address in the e-mail field
When I click on the Next button
Then I should see a newly added customer in the list of customers filed by their company name

Scenario: Blank Company Name
Given I am in the New Customer window
When I leave the company name field blank
When I click on the Save button
Then I should be presented with an error saying so

These criteria are not exhaustive, but should suffice for the purposes of this post.

Installing SpecFlow and White


SpecFlow is available on NuGet. However,  at the time of this going to the metaphorical press, the latest version of White isn't. You can work around this by downloading the White assemblies and then adding references to White.Core.dll and White.NUnit.dll.

When writing acceptance tests, it is a good idea to isolate them from the code under test by creating a separate class library project in your Visual Studio solution.

Gettings Started with SpecFlow


The acceptance criteria as well as the user story definition go into a SpecFlow feature file. You can create one on Visual Studio (Add-> New Item -> SpecFlow Feature file). SpecFlow feature files may contain an arbitrary number of acceptance tests. Moreover, acceptance tests for the same feature can be split across multiple feature files.

A SpecFlow step definition file that is used to instrument your tests is generated whenever you create a SpecFlow feature file. This is where you specify the instrumentation that allows you to perform the actions described using your DSL.

You can use the stub below to write your own SpecFlow step definition file for the acceptance criterion described in our example.
[Binding]
public class SavingCustomerInformation
{
    [Given("I am in the New Customer window")]
    public void GivenNewCustomerWindow()
    {
    }

    [When("I enter a company name in the company name field")]
    public void WhenEnterCompanyName()
    {
    }

    [When("I enter a contact e-mail address in the e-mail field")]
    public void WhenEnterEmail()
    {
    }

    [When("I click on the Save button")]
    public void WhenClickSaveButton()
    {
    }

    [Then("I should see a newly added customer in the list of customers filed by their company name")]
    public void ThenNewCustomerInList()
    {
    }

    [When("I enter a company name that has been already added in the company name field")]
    public void WhenEnterExistingCompanyName()
    {
    }

    [Then("I should be presented with an error saying so")]
    public void ThenError()
    {
    }

}
The snippet given below is a plain piece of C# code, the only interesting bit are the special annotations [Given], [When], and [Then] that specify that the annotated method will be executed upon running a statement declared in the annotation.

White to the Rescue


It is reasonable to expect that such a method should perform UI manipulations such as populating forms and clicking on buttons. Working with White starts with launching or attaching to an existing process of an application we want to test.

Application applicationUnderTest = Application.Launch(pathToApplication);

Every acceptance tests of ours has the same pre-condition block:
Given I am in the New Customer window

That translates into finding an appropriate window:
//the window object will be used in many methods, so it is reasonable to make it a member variable
private Window newCustomerWindow;

[Given("I am in the New Customer window")]
public void GivenNewCustomerWindow()
{
    this.newCustomerWindow = SavingCustomerInformation.applicationUnderTest.GetWindow("New Customer");
}

Our scenarios also involve populating some fields which can be also easily done with White. Essentially, when you need to manipulate any control with White you first find it by either its name or any other criteria and they you perform manipulations on it. The two methods below illustrate this technique applied to writing in a text field and clicking on a button.
[When("I enter a contact e-mail address in the e-mail field")]
public void WhenEnterEmail()
{
    TextBox emailTextBox = this.newCustomerWindow.Get<TextBox>("emailTextBox");
    emailTextBox.Enter("some@email.com");
}

[When("I click on the Save button")]
public void WhenClickSaveButton()
{
    Button saveButton = this.newCustomerWindow.Get<Button>("saveButton");
    saveButton.Click();
}

Putting It All Together


Speaking about some certain aspects of using SpecFlow and White, it is still necessary to have an entire picture of the whole testing suite, that is given below.

[Binding]
[Binding]
public class SavingCustomerInformation
{
    private static Application applicationUnderTest;
    private Window newCustomerWindow;
    private const string COMPANY = "Some Company";

    [BeforeFeature]
    public static void LaunchApplication()
    {
        SavingCustomerInformation.applicationUnderTest = Application.Launch(@"..\..\..\Application\bin\Debug\Application.exe");
    }

    [Given("I am in the New Customer window")]
    public void GivenNewCustomerWindow()
    {
        this.newCustomerWindow = SavingCustomerInformation.applicationUnderTest.GetWindow("New Customer");
    }

    [When("I enter a company name in the company name field")]
    public void WhenEnterCompanyName()
    {
        TextBox companyTextBox = this.newCustomerWindow.Get<TextBox>("companyTextBox");
        companyTextBox.Enter(COMPANY);
    }

    [When("I enter a contact e-mail address in the e-mail field")]
    public void WhenEnterEmail()
    {
        TextBox emailTextBox = this.newCustomerWindow.Get<TextBox>("emailTextBox");
        emailTextBox.Enter("some@email.com");
    }

    [When("I click on the Save button")]
    public void WhenClickSaveButton()
    {
        Button saveButton = this.newCustomerWindow.Get<Button>("saveButton");
        saveButton.Click();
    }

    [Then("I should see a newly added customer in the list of customers filed by their company name")]
    public void ThenNewCustomerInList()
    {
        ListBox customersList = this.newCustomerWindow.Get<ListBox>("customersListView");

        Assert.NotNull(customersList.Items.Find(x => x.Text == COMPANY));
    }

    [When("I leave the company name field blank")]
    public void WhenLeaveBlankCompanyName()
    {
        TextBox companyTextBox = this.newCustomerWindow.Get<TextBox>("companyTextBox");
        companyTextBox.Enter(string.Empty);
    }

    [Then("I should be presented with an error saying so")]
    public void ThenError()
    {
        Assert.NotNull(this.newCustomerWindow.Get(SearchCriteria.ByText("Company name is empty")));
    }

    [AfterFeature]
    public static void KillApplication()
    {
        SavingCustomerInformation.applicationUnderTest.Kill();
    }
}

Having the whole acceptance test code at a glance, it is evident that actual testing occurs in methods annotated with [Then]. Such methods contains Assert expressions and it is possible to make use either MSTest or NUnit.

Methods that have attributes of [BeforeFeature] and [AfterFeature] are executed before and after a feature respectively. In the code snippet above, such methods are used for launching and killing the application. Since the methods carrying such annotations are required to be static, the member variable containing a reference to the application under test is also declared as static.

Running your Tests


Since SpecFlow tests are compiled into DLL files, it is not possible to run them on their own. There are multiple tools that can do this for you, ranging from the built-in in Visual Studio MSTests to SpecRunner, which comes as a separate dependency in NuGet, and NUnit.

SpecRunner produces neat and most human readable HTML reports, while NUnit allows you to run individual scenarios. However, when using NUnit, you should bear in mind that the [BeforeFeature] annotation behaves like [BeforeScenario]. Thus, if you are launching an application under test in such methods, it will be executed on each acceptance test instead being run once for all the tests of a given user story.

If you'd like to switch runner, you can either go to Tools -> Options -> SpecFlow -> General -> Test Runner Tool or just modify app.config file of a test project. If you want to use NUnit as a runner, then the only option is modifying app.config, as NUnit is not present in the Tools drop-down menu.
<specflow>
    <unittestprovider name="NUnit">
</unittestprovider>
</specflow>

More SpecFlow Goodies


SpecFlow step definition annotations can also use regex matching, thereby allowing you to pass parameters into generic step definitions. For example, instead of simply stating:
When I enter a company name in the company name field

You can write:
When I enter ‘Acme Ltd.’ in the company name field
Then I should see a message saying ‘A new company has been added’
And then receive these parameter values in your code:
[When("I enter ‘(.*)’ in the company name field")]
public void WhenEnterCompanyName(string companyName)
{
    TextBox emailTextBox = this.newCustomerWindow.Get<TextBox>("emailTextBox");
    emailTextBox.Enter(companyName);
}

[Then("I should see a message saying ‘(.*)’")]
public void ThenEnterCompanyName(string message)
{
    Assert.NotNull(this.newCustomerWindow.Get(SearchCriteria.ByText(message)));
}
Of course, it’s not necessary to have acceptance test written in this way, as it might make them brittle and less robust, but it’s nice to have such an opportunity, just in case.

Now Write Some Code for Your Application


If you were to run your tests now, they would fail (or to be precise, they'd throw an exception as the application to test still doesn't exist). That is not a problem, as the whole point of TDD is to use your tests  to guide your code. You can now write your code (writing any tests that may entail first), writing just enough code to make the tests pass.

You can download all of the source code for the example application, including the tests and the application, here.
Pontus is ready and waiting to answer your questions