Recently, I spent a few days getting to know the testing ecosystem around AngularJS, specifically related to Unit Testing and End-to-End testing. Jasmine (unit-testing) and Protractor (end-to-end) are the two prescribed frameworks for those.
With that in mind, I looked around for some resources online as to how BDD changes the development process. The first article to peak my interest was Functional testing with cucumber and protractor. Being that BDD differs from TDD in that a feature/behavior is being tested, rather than the functionality of a module/unit, bridging the conceptual gap was a little shaky. In the middle of the Functional testing…, this graphic came up that helped to elucidate the process:
Take a look at the graphic: you can see that unit-testing still exists within the context of the BDD, but now it’s involved within the development of the system at large. Red-Green-Refactor is still there, but within the greater BDD loop of focusing on the scenario.
Testing: BDD ? Scenarios
Whats in a Story is a great article that focuses on the scenario approach to writing features in BDD. Boiled down, when we write out what the features will be:
1. The scenario title should say what’s different
You should be able to line up the scenarios side by side, and describe how they differ using only the title.
2. The scenario should be described in terms of Givens, Events and Outcomes
…adopt this vocabulary of “given/when/then”…
To build out the scenarios in Mailist, these rules were used. Here’s an example scenario:
Scenario: A user loads a list and generates a queue Given there are no emails And there is no template And there is no cached data When the user loads a csv of data Then the queue list should be populated And there should be relevant field headers
Figure 2: example scenario
Testing: Protractor ? End-to-End
Looking at the chart in Figure 1, since the features we build involve multiple parts of the system, testing at the integration level makes sense. The Angular team has done a great job providing a tool just for that: Protractor. It’s compatible with the Jasmine syntax, and uses a convenient element selection syntax for performing actions on target elements. For example:
var input = element(by.css('input')); input.sendKeys('123'); expect(input.getAttribute('value')).toBe('Foo123');
Check out the docs for more info.
Testing: Jasmine ? Unit-Testing
Here we unit test with the popular Jasmine test framework. For each of the scenarios, now a series of internal modules become clear. This was the aha moment. For each scenario, the internal requirements become clear. And just like the chart in Figure 1, I’m back to the Red-Green-Refactor cycle, defining and testing module behavior in the typical TDD fashion.
The one thing that sticks out here with Angular is testing directives. There are a couple of methods I’ve seen online recommended: using E2E for testing directives, or using the internal angular directive compilation. Both are straightforward, however I was having trouble automating the file input through the directive compilation method because of browser security policies. I’d rather not have to script launching browsers with special access policy flags, so I left those tests to Protractor.
So, in short, BDD with Angular is straightforward using Protractor and Jasmine for E2E and unit-testing. By sticking to the chart in Figure 1, building out scenarios, and sticking with givens/events/outcomes to outline our scenarios, we have a clear idea of how our app evolves.
Jump over to Github and browse the code for Mailist. Then take a look at these links for the tools mentioned:
For my favorite link on Angular testing, check out Year of Moo’s Full-Spectrum Testing with AngularJS and Karma. It’s centered around Mocha, Chai, and Karma as a testing framework, but the concepts for testing each part of an Angular app is broken down here.
Let me know what you think on Twitter @lintuxvi