BDD with Rug

Russ Miles
8 min readOct 26, 2016

--

BDD Testing with Rug

Testing. Sounds simple doesn’t it? You create an appropriate context, make something important happen, and assert that the behaviour was as expected.

Simple.

And it is.

Except when it’s really not.

The Devil is in the Context

The challenge of testing is most typically in the very first and last steps: Setting up the Context and then asserting validity in the Resulting Context. Or in the parlance of Behaviour Driven Development: Specifying what is “Given” and then asserting “Then”.

Conventional wisdom says that defining and working with an appropriate context should be simple. If the solution is not simple and elegant then the fault lies with the system you are testing, ergo the unit-under-test must not be well-designed.

But there are times when the context is essentially complex even when the unit-under-test is simple and well-designed. Frequently this is in the case where you have a unit-under-test whose purpose is to integrate with lots of other places and to work with lots of different contexts.

Such is the case when you’re writing new Rug Reviewers, Editors, and even Generators.

Meeting the Challenge of Context with Rug Testing

When we were designing Rug, the whole team felt that we had to have a first-class testing story. The rationale goes that unless you can develop tests, ideally first, to establish real confidence in your Editors and Generators, you’re not going to feel comfortable turning them loose on your codebases.

To ensure developers would have confidence in their Editors and Generators we included a complete testing Domain Specific Language (DSL) in Rug. In this DSL you can define a context to establish for your Editors and Generators, as well as use that context to assert that the outcomes of your Editor or Generator is as expected.

What do we mean by context? In the case of Rug Generators the context is the new project under creation starting from an empty beginning. Rug Editors and Rug Reviewers (a topic for a future article) work on an existing project as their context. Finally comes Rug Executors (another topic for a future article), whose context is that of multiple projects and associated information.

Therefore in order to support testing your Rug Generators, Editors and Reviewers the first context that Rug Testing must help you set up is that of a project.

Step 1: A Scenario and a Given Context

Let’s look at the test-driven process for creating a new Editor, in this case a real-world Editor that adds Hystrix circuit-breaker infrastructure support to an existing Spring Boot application.

NOTE: The real and complete Editor can be found in the spring-boot-common-editors project on GitHub.

All Rug sources are contained within a .atomist directory in your project, and we’ll be focussing on the tests subdirectory first.

For our first step we’ll consider a happy-day scenario. We create a file called AddHystrix.rt in our .atomist/tests directory.

In the AddHystrix.rt file you then declare that this is a Rug test scenario with a meaningful scenario description:

You need at least one scenario per Rug testing .rt file, but you can have more than one if you like as well. We’ll be adding further scenarios to this file towards then end of this article.

With our scenario declared, it’s now time to meet our first challenge: what is our starting-point project context that we need to establish to test our Editor against? For our purposes here we’ll create a given block in our Rug test that uses the special ArchiveRoot directive.

ArchiveRoot states that we’d like to use the current project, the one with the .atomist directory in, as the baseline starting point for testing our new Editor against. The complete given block looks like:

The indentation is optional but makes things a little easier to read.

ArchiveRoot is a convenient starting point, but we could have explicitly specified filenames and the file contents at this point as well. We’ll see how to do this later on in this post.

At this point our Rug test contains the following:

We’ve established our starting-point project context really easily and now it’s time to invoke the unit-under-test that is our soon-to-be-written Rug Editor.

Step 2: When Something Happens

So far we have set up the initial context upon which our Editor is expected to operate. We could have simply called the Editor we’re going to create in the given block if we’d wanted, but this would violate the expected flow of a Behaviour Driven test.

Instead Rug tests typically have a when block to specify what you expect to actually happen. In this case we expect to execute a Rug Editor against the given project context using:

All these lines are saying is that we want to call an Editor named AddHystrix. So far we’ve not created our AddHystrix Editor but, following the test-first principles, we next need to set up some expectations for what should have happened to the initial given project context once our soon-to-be-written Editor has been executed.

Step 3: Then assert the new context

Rug testing provides a then block that asserts the changes that should result from the when block’s editor invocation on the project context originally set up in the given block.

The then block’s context is the resulting project context and so we can execute the following assertions against that context:

There’s a lot happening here, but the main thing to focus on is that you are simply running a set of assertions against the context of a project. You’re testing the fact that a particular file exists and then testing that a number of changes have been applied to the expected files within the project.

Step 4: Write the Rug…

Now our AddHystrix.rt is a complete, failing test we have the license to write some Rug! First you create a new Rug Editor in the .atomist/editors directory called AddHystrix.rug and give it the following contents:

The first Editor in the .rug file must have the same name as the rug file itself, in our case this is AddHystrix.

Step 4.1: Manipulating the POM

The first thing our AddHystrix Editor must do to satisfy our Rug test is to create the dependencyManagement section for Spring Cloud in the target project’s pom.xml:

To apply this section to our pom we next select the pom type that in turn selects the pom.xml file for our changes to be applied to.

We then instruct the pom type to perform two modifications: add our dependencyManagement section and add the spring-cloud-starter-hystrix dependency itself:

Step 4.2: Adding the `EnableCircuitBreaker` Annotation to the Spring Boot Application class

Last but not least you need to add the EnableCircuitBreaker` annotation to turn on the Hystrix circuit-breaking features:

The annotateBootApplication function on the spring.bootProject type knows how to detect the Spring Boot Application class, adds the specified import and then to add the specified annotation. Also notice the fact that we didn’t need to use the begin/end block here as we only have one statement inside the with selector.

We’ve done quite a bit here but now we should be able to run our AddHystrix.rt test and all will be well.

But there is a still a problem… Right now this Editor could actually be applied to any project. It may not modify much, but it would be better if our Editor could detect it was being used on an appropriate Spring Boot project rather than relying on modifications simply failing.

Let’s extend our Editor to use Rug predicates so that we can detect and stop the Editor if it is being applied to an inappropriate project.

Testing-First for Predicates

We want to ensure that the AddHystrix editor only modifies appropriate Spring Boot projects, and so it’s time to introduce the concept of predicates.

First though, following our BDD-Test-First approach we need to extend our testing to incorporate this new scenario:

This scenario sets up an Empty project this time and then runs our AddHystrix Editor, finally asserting that the response is in fact NoChange, which is what we’d expect.

Next we need to extend our Editor with the right predicates to meet this new scenario by describing the sorts of projects we want AddHystrix to be applied to.

Implementing Predicates

Predicates in Rug are a form of selector, much as we used the with statement before to select that we wanted to work with the project’s pom using the pom type.

We need two predicates and we’ll declare one in it’s own .rug file so it can be reused elsewhere, while we’ll declare the second along with our AddHystrix Editor.

The following goes in an IsMaven.rug file in the editors directory:

We’ll go into detail more on predicates in future posts, but for now it’s best to think of them as nothing more than a selector that ensures the with statements are true. In the case of the IsMaven predicate, the predicate ensures the project has a pom file.

Lastly let’s add another predicate and this time inside the AddHystrix.rug file after our Editor:

This predicate takes the protection a little further by specifying that it will only select a project if it follows a collection of Spring Boot conventions.

With the predicates to hand, it’s now time to actually apply them to protecting our Editor so that it will not run unless these predicates are satisfied.

Applying Predicates as Preconditions to an Editor

Applying predicates to an Editor is as simple as declaring those predicates as preconditions. Preconditions need to be specified as the first detail in your Rug Editor, one precondition per predicate:

And that’s it, we’re done! Now when we execute our new test scenarios all should be well as these preconditions will protect us from executing this Editor against an inappropriate target project.

Closing Comments on Rug Testing

Rug provides a complete Domain Specific Language that makes it simple and productive to use BDD Tests. In this article you’ve seen how to apply a Test-First BDD style to writing your own Editors, and the same approach can be used for your Generators and (coming soon) Reviewers and Executors also.

The sample code in this article is in fact simply a walk-through of the real test scenarios and Editor in the spring-boot-common-editors Atomist project template.

This article is simply a walk-through of real test and editor code in the Atomist spring-boot-common-editors Github repository.

The Rug Testing DSL shoulders the hard work of setting up and asserting the appropriate context for your scripts. This allows you to focus on your code and apply the same professional development skills you use everyday in other languages to the creation of Rug scripts.

Documentation for the Rug Test DSL is now available in the Atomist Documentation. If you’d like to find out more or share your experiences with Rug the best place to head is to the Atomist Community slack.

--

--

Russ Miles

People, Team and Organizational Developer. Writer, psychologist, speaker and humanistic Head of Engineering. https://twitter.com/russmiles