Tag Archives: bdd

SpecFlow remains my top choice for automated integration testing. I love writing cute little cukes and putting them together in different ways to create different test scenarios. And one of my favorite cuke tricks is using tables to define an object, which I wrote about some time ago.

The CreateInstance<T> extension method provides an easy way to convert that table data into objects for testing, but I really think there should be a better way to populate child properties of complex objects.

But you can’t. Well, you can, but the address property won’t be populated. I didn’t like that, so I decided to grow my own. It works by identifying the child properties in the table and creating sub-tables, then using reflection to find and set the property on the result object. It works recursively, too, so you could even go n properties deep (i.e., address.state.abbreviation).

At its core, it’s just using CreateInstance<T> so you get all the niceties that go along with that. Note also that it only works with the 2-column, vertical tables with field and value columns. I called my extension method BuildInstance since CreateInstance was already taken. Here it is… Enjoy!

Share this:

Like this:

My team has been using SpecFlow to verify that our data access components are working correctly. In an effort to write repeatable tests that won’t pollute the database, we’ve decided to wrap each scenario in a transaction.

Creating and rolling back the transactions is very simple to do with SpecFlow’s BeforeScenario & AfterScenario hooks.

By including these hooks, you’re placing your test scenarios in the loving embrace of a transaction scope. The act of instantiating the TransactionScope will update the ambient transaction that will be used by all subsequent code unless you explicitly tell it to do otherwise.

If you’re testing code that uses TransactionScope itself, using TransactionScopeOption.Required will allow the code to use the ambient transaction if one exists. Note that this is the default value, so it’s what you’re using if you’re not explicitly specifying an option. However, the other TransactionScopeOption values will cause code to execute outside your test scenario’s ambient transaction by either creating a new/different transaction (RequiredNew) or executing outside the transaction (Suppress).

Share this:

Like this:

I’ve written [several] [posts] [in] [the] [past] about my team’s adoption of SpecFlow and BDD, and I’m still loving it several months later. The large project that we started with has nearly 10,000 lines of code and 93% code coverage. We’ve gone through several large refactors, and each time we walk away with a high level of confidence that no functionality was lost or affected negatively. It’s been a really great experience.

One of the challenges of adoption was just learning the Cucumber step definition syntax, or rather, how to write cukes. For getting started, I recommend taking a look at this page for a good list of descriptions, scenarios, and examples. If you’re using SpecFlow, you may also want to check out their step definition documentation on GitHub.

Once you’ve got the basic syntax down, the hard part begins. My team hasn’t had much formal discussion about Cucumber best practices, and we’re still learning what works and what doesn’t. If you look around online, you can find a few good articles with helpful suggestions, though.

Here’s a great post that I recommend reading. This article offers advice on just about every aspect of creating and managing your cukes, from feature files to tags to running and refactoring.

I also found this post from EggsOnBread to be very helpful. All of the recommended practices are good. This was one of the first articles I read when I was getting started, and it’s served me well. I’ll be honest, though–many of the points didn’t stick during my initial read. It became much more valuable after spending several months working with Cucumber and then re-reading.

Share this:

Like this:

I’ve been using SpecFlow pretty regularly for a few weeks now, and I must say, I’m a fan. I find that it’s a lot easier to do test-first development because I’m writing the test in human-readable, business language.

One of the ideas that I didn’t understand right away was how to re-use generated step definitions across features and scenarios. ScenarioContext and FeatureContext give you great options to handle this, though. Let’s check out an example using a modified version of the default scenario SpecFlow generates with a new feature file:

Scenario: Add two numbers
Given I enter 50 into the calculator
And I press plus
And I enter 70 into the calculator
When I press enter
Then the result should be 120 be displayed

When I generate step definitions, I might end up with a class that looks like this:

Okay, not bad. A logical next feature might be subtraction. Some of the steps, like entering numbers and pressing enter, are shared. It would be nice if we could re-use those, but they’re configured to manipulate private variables in the Calculator_AddSteps class. So let’s do some refactoring! Instead of using a member-level variable, I can store my Calculator object in the ScenarioContext, making it accessible to other steps being executed in the same scenario.

This is overkill for such a simple example, but I separated my shared steps into a new step definitions file. The final solution has three classes for the step definitions: Calculator_AddSteps, Calculator_SubtractSteps, and Calculator_SharedSteps.

Here’s the final solution, broken up by file:

Calculator_Add.feature

Feature: Calculator_Add
In order to avoid silly mistakes
As a math idiot
I want to be told the sum of two numbers
Background:
Given I have a calculator
Scenario: Add two numbers
Given I enter 50 into the calculator
And I press plus
And I enter 70 into the calculator
When I press enter
Then the result should be 120 be displayed

Feature: Calculator_Subtract
In order to avoid silly mistakes
As a math idiot
I want to be told the difference between two numbers
Background:
Given I have a calculator
Scenario: Subtract two numbers
Given I enter 70 into the calculator
And I press minus
And I enter 50 into the calculator
When I press enter
Then the result should be 20 be displayed

I’ve been doing my own, made-up version of BDD for a while. For example, I would have a function that calls several sub-methods. I’d mock the sub-methods and write tests to verify that the sub-methods were called. Then I’d move to the next “layer” by implementing the sub-methods in a similar fashion, repeating until I hit the bottom layer, where the actual work happens.

Here’s how you can get started with SpecFlow and Visual Studio. This tutorial is basically a modified version of the Project Setup Guide on the SpecFlow site. I ran into a couple issues with their tutorial, though, and their tutorial also doesn’t get much into implementing the application logic to fix unit tests once they’re generated.

Installing SpecFlow

SpecFlow is included in the Visual Studio Extensions Gallery, so installing it is a breeze.

Open Visual Studio, and go to Tools > Extensions and Updates (Extension Manager in VS2010)

Select the Online gallery

Search for “SpecFlow”

Install it!

Nice, now you’re ready to create your first test project.

Creating your first test project

SpecFlow tests are defined as “features” that have multiple scenarios. There is a small amount of project setup that needs to be done, but it’s not too bad and you can be up and running in just a few minutes.

The example shows a simple AddingMachine class with implemented steps to pass the default feature scenario

Feature: MyFirstFeature
In order to avoid silly mistakes
As a math idiot
I want to be told the sum of two numbers
@mytag
Scenario: Add two numbers
Given I have entered 50 into the calculator
And I have entered 70 into the calculator
When I press add
Then the result should be 120 on the screen

That’s it! Now you should have a passing unit test that verifies the business-language requirement. You can add more scenarios to your feature file with different values and/or steps. Note that if you add more steps, you’ll probably need to re-generate step definitions. When you do this, only new step definitions will be generated. I recommend using the Copy methods to clipboard button in the Generate Step Definitions dialog to avoid overwriting the previously created and implemented step definitions.

Share this:

Like this:

Hi, I’m Adam. This is my blog.

I started this blog as a personal searchable repository of things I've learned and figured out. It evolved into a mechanism to facilitate personal growth, and now it's turned into a bit of a hobby. I enjoy writing about software development, my professional life, and related topics.

I love to hear from readers, so please feel encouraged to leave comments on anything you read here.

Follow Blog

Enter your email address to follow this blog and receive notifications of new posts by email.