We started describing the acceptance criteria in terms of scenarios, which took the following form:
- Given some initial context (the givens),
- When an event occurs,
- then ensure some outcomes.
BDD approach to testing provides a template for capturing story’s acceptance criteria as a set of sentences, like in the real conversation. At the same time it provides an answer on:
- where to start when writing tests
- what to test and what not to
- how much to test in one go
- what to call a tests
- how to understand why test fails
For more details check Dan North’s blog at https://dannorth.net/introducing-bdd/
NOTE: Core Jasmine functionalities are described using pseudo code.
In terms of BDD, Jasmine provides
describe() function which serves as a container for a group of related specifications tests (story, feature, scenario). In addition to that, Jasmine provides
it() function that’s used as a container for a specification behaviour validation (acceptance criteria, specification, spec). Desired specification implementation behaviour is verified via expectations.
- Used together, describe, it and expectations helps express story and acceptance criteria as a complete sentence / conversation
describe('an order') it('sums the prices of its line items') expect(order.total == 100.00)
- Matcher implements a boolean comparison between the actual value and the expected value. It is responsible for reporting to Jasmine if the expectation is true or false. Jasmine will then pass or fail the spec.
describe('an order') it('sums the prices of its line items') expect(order.total).not.toBe(0.00) expect(order.total).toBe(100.00)
- Hooks in Jasmine can be used to provide shared setup and/or tear-down before/after each specification in describe block is called
describe('an order') beforeAll('run once before all specs are called') beforeEach('run before each spec is called') it('sums the prices of its line items') expect(order.total == 100.00) afterAll('run tear-down once after all of the specs are called') afterEach('run tear-down after each of the specs is called.')
- Spies provides a test double function. A spy can stub any function and track calls to it and all its arguments
describe('an order printer') spyOn('printerObject', 'printOrderMethod') it('prints the order') printerObject.printOrderMethod() expect(printerObject.printOrderMethod() to have been called)
- Jasmine also provides a mock Clock object that can be used to test time dependent code and mock dates. NOTE: It is important to uninstall the clock after the test to restore the original functionality!
describe('clock') beforeEach() jasmine.clock.install() afterEach() jasmine.clock().uninstall(); it('sets the clock to tomorrow') jasmine.clock().mockDate(tomorrow) jasmine.clock.tick(1 day) expect (currentDate === tomorrow)
- Testing code that requires asynchronous operations is supported by Jasmine. There are three ways to indicate a function is asynchronous:
- by taking an optional callback parameter,
- by returning a promise,
- or by using the async keyword in environments that support it.
- Check simple business scenario implemented with Jasmine BDD testing framework at: All Things Angular - Jasmine BDD Testing Framework #angular
- Check custom Jasmine configuration example at: All Things Angular - Jasmine BDD Testing Framework #Multiple Jasmine run configurations
Having out of the box integration with Jasmine BDD testing framework, Angular provides everything needed to start building high quality testable applications. Applying BDD approach to software development assures that story’s acceptance criteria are working as expected and are bringing business value.