CSC/ECE 517 Fall 2014/ch1b 28 cg
Behavior-Driven Development and Test-Driven Development
Background
What is Test-Driven Development?
Test driven development(TDD) is a software development process that relies on the repetition of a very short development cycle: first the developer writes an (initially failing) automated test that defines a desired improvement or new function, then produces the minimum amount of code to pass that test, and finally refactors the new code to acceptable standards.
Development cycle
A typical TDD development cycle<ref >software development process</ref> could be simply described as followed<ref>Beck, K. Test-Driven Development by Example, Addison Wesley - Vaseem, 2003</ref>
- Write an automated test case before write code. While writing the automated tests, you must take into account all possible inputs, errors, and outputs. This way, your mind is not clouded by any code that's already been written.
- Run automated test, the test should fail—indicating that the code is not yet ready.
- Program to pass the test. Since there's already an automated test, as long as the code fails it, it means that it's still not ready. The code can be fixed until it passes all assertions.
- Begin cleaning up codes and remove redundancy via refactoring<ref>Refactoring: Improving the Design of Existing Code</ref>. As long as the code still passes the test, it means that it still works. You no longer have to worry about changes that introduce new bugs.
- Repeat the whole process.
Example of TDD
Below we start develop following the rules of TDD. We are given requirements to implements a certain function. Before writing any code, we should take all these requirements into account. Based on these requirements, We will use JUnit to write test.
Requirements: *Create a simple String calculator with a method int Add(string numbers) *The method can take 0, 1 or 2 numbers, and will return their sum (for an empty string it will return 0) *Allow the Add method to handle an unknown amount of numbers *Allow the Add method to handle new lines between numbers (instead of commas). *The following input is ok: “1\n2,3″ (will equal 6) *Support different delimiters
Suppose we had a String calculator and write out test for the requirement 1.The first set of tests verifies that up to two numbers can be passed to the calculator’s add method. If there’s more than two or if one of them is not a number, exception should be thrown. Putting “expected” inside the @Test annotation tells the JUnit runner that the expected outcome is to throw the specified exception.
Test: package com.tdd.test; import org.junit.Test; import com.tdd.stringCalculator; public class StringCalculatorTest { @Test(expected = RuntimeException.class) public final void whenMoreThan2NumbersAreUsedThenExceptionIsThrown() { StringCalculator.add("1,2,3"); } @Test public final void when2NumbersAreUsedThenNoExceptionIsThrown() { StringCalculator.add("1,2"); Assert.assertTrue(true); } @Test(expected = RuntimeException.class) public final void whenNonNumberIsUsedThenExceptionIsThrown() { StringCalculator.add("1,X"); } }
The first tests should always be failed because we do not have a string calculator yet. So we should create one.
Implementation: package com.tdd.stringCalculator; public class StringCalculator{ public static final void add(final String numbers) { String[] numbersArray = numbers.split(","); if (numbersArray.length > 2) { throw new RuntimeException("Up to 2 numbers separated by comma (,) are allowed"); }else{ for (String number : numbersArray) { Integer.parseInt(number); // If it is not a number, parseInt will throw an exception } } } }
We should keep in mind that the idea behind TDD is to do the necessary minimum to make the tests pass and repeat the process until the whole functionality is implemented. At this moment we’re only interested in making sure that “the method can take 0, 1 or 2 numbers”. Run all the tests again and see them pass. Then we could repeat the above steps to implement requirement 2.
Main Tools
The following is a representative list of common TDD tools.
cpputest | csUnit(.Net) | CUnit | DUnit(Delphi) |
DBFit | DBUnit | DocTest(Python) | Googletest |
HTMLUnit | JMock | JUnit | Moq |
NDbUnit | NUnit | OUnit | PHPUnit |
PyUNit(Python) | SimpleTest | TestNG | TestOoB(Python) |
Test::Unit(Ruby) | VBUnit | XTUnit | xUnit.net |
What is Behavior-Driven Development?
Definition
BDD(Behavior Driven Development) is a synthesis and refinement of practices stemming from TDD(Test Driven Development) and ATDD(Acceptance Test Driven Development). Behavior driven development combines the ideas from domain-driven design and object-oriented analysis design, providing the collaboration between business interests and technical insights with shared tools and shared process to collaborate on software development.
During the "Agile specifications, BDD and Testing eXchange" in November 2009 in London, Dan North gave the following description of BDD:
BDD is a second-generation, outside-in, pull-based, multiple-stakeholder, multiple-scale, high-automation, agile methodology. It describes a cycle of interactions with well-defined outputs, resulting in the delivery of working, tested software that matters."
History
In 2007, a group of Agile practitioners, including Dan North and Dave Astels, started rocking the boat, with presentations and tool development work. They believed that it is possible to write high quality, well-tested, reliable, and maintainable code, and miss the point altogether. As software developers, the main goals is to help customers to solve problems. Behavior driven was a response to the lack of any specification within TDD of:
- What to test and what not to test
- How much to test in one go
- What to call the test
- How to understand why a test fails
They started from the common use of story template that starts like this:
As a [role], I want a [feature], So that [I gain some benefit].
Dan North and his collaborator created a template to capture a story’s acceptance criteria and described it as scenarios. The scenarios break the story into constituent segments and can be automated for analysis. It took the following form:
Given some initial context (the givens), When an event occurs, Then ensure some outcomes.
Based on this, North and others developed the Behavior driven framework over a period of years, finally framing it as a communication and collaboration framework for both technical and nontechnical participants.
Dan North created the first ever BDD framework, JBehave,followed by a story-level BDD framework for Ruby called RBehave which was later integrated into the RSpec project. He also worked with David Chelimsky, Aslak Hellesøy and others to develop RSpec and also to write "The RSpec Book: Behaviour Driven Development with RSpec, Cucumber, and Friends". The first story-based framework in RSpec was later replaced by Cucumber mainly developed by Aslak Hellesøy.
In 2008, Chris Matts, who was involved in the first discussions around BDD, came up with the idea of Feature Injection, allowing BDD to cover the analysis space and provide a full treatment of the software lifecycle from vision through to code and release.
Principle
Behavior driven development presents a framework of activity based on three core principles:
- It's all behavior: Business and Technology should refer to the same system in the same way
- Where the business value: Any system should have an identified, verifiable value to the business
- Enough is enough: Up-front analysis, design and planning all have a diminishing return
BDD is very much focused on “Getting the words right” and this focus is intended to produce a vocabulary that is accurate, accessible, descriptive and consistent for analysts, testers, developers, and the business, the shared process and tools eliminate some of the ambiguity and miscommunication between them.
Practice
Let's look at one example of the practice of BDD: A developer is going to develop a web based email program. The development and supervisor has given the flowing specification of the email program:
As a product owner, I would like to get a web based chatting system by which I can compose message on-line and can send message.
Then the developer follows the test driven development practice and make the flowing test cases:
This program should send message of the receiver address is valid. This program should send message even if the subject line is empty. This program should send message even if the body is empty
The developer now needs to find as many possible test cases as possible. However, this step is cumbersome and the test case may not even be exhaustive.
Now we come to the point of trying to find a way to let product owner give developers a requirement that include all possible behavior of the module as well as its corner point. And it is given in such format that can be understood both by technical person and non technical person.
This is where DDB comes into its place. To write the requirement, the only one rule to be followed is to use Given-When-Then steps:
Given that a web based message module has been developed And I am accessing it with proper authentication When I shall write sender message address in To field And write something in body text area which excepts rich text And press or click send button Then my message will be sent And the event will be logged in log file.
BDD produced such a vocabulary that is accurate, descriptive and consistent.
Specialized tooling support
There are several different examples of BDD software tools in use in projects today, for different platforms and programming languages. Possibly the most well-known is JBehave, which was developed by Dan North. The following is an example taken from that project:[13]
Scenario: trader is not alerted below threshold Given a stock of symbol STK1 and a threshold of 10.0 When the stock is traded at 5.0 Then the alert status should be OFF Scenario: trader is alerted above threshold Given a stock of symbol STK1 and a threshold of 10.0 When the stock is traded at 11.0 Then the alert status should be ON
JBehave maps textual steps to Java methods via CandidateSteps. The scenario writer need only provide annotated methods that match, by regex patterns, the textual steps.
public class TraderSteps { private Stock stock; @Given("a stock of symbol $symbol and a threshold of $threshold") public void aStock(String symbol, double threshold) { stock = new Stock(symbol, threshold); } @When("the stock is traded at $price") public void theStockIsTradedAt(double price) { stock.tradeAt(price); } @Then("the alert status should be $status") public void theAlertStatusShouldBe(String status) { ensureThat(stock.getStatus().name(), equalTo(status)); } }
The code has a method for every type of clause in a scenario. JBehave can identify which method goes with which clause by using annotations and will call each method in order. JBehave has built-in support for parsing terms out of the template and passing them to methods in the test code as parameters. The test code provides an implementation for each clause type in a scenario which interacts with the code that is being tested and performs an actual test based on the scenario. In this case:
- The aStock method reacts to a Given clause by setting up the initial symbol stock
- The theStockIsTradedAt method reacts to a When clause by passing the price of the stock.
- The theAlertStatusShouldBe method reacts to a Then clause by firing alerts when reach the specified status.
This code is a bridge between a text file with a story and the actual code being tested. In order to run the tests, JBehave requires some code that identifies the text files which contain scenarios and which inject dependencies (like instances of Stock) into the test code.
Behavior-Driven Development VS. Test-Driven Development
Advantages of Behavior Driven Test
- Better commitment and buy-in:
BDD places heavy emphasis on the software’s business value. It forces the business to justify the priority by showing concrete value. It also requires the development teams to embrace the prioritizes set by business. The team won’t build useless feature merely for the sake of productivity.
- Ubiquitous domain language:
BDD provides a shared domain language that the business team and the technique team can understand. It reduces the complexity and makes barrier-to-entry much lower for new members. It also narrows the domain knowledge gap between the team members. For example, team members who are away from the real business, have a hard time understanding and questioning the business requirement, leading to misunderstanding. BDD encourages a generalizing specialist attitude in team members, helping with other eXtreme programming practices.
- Right focus of the project:
BDD can help the developer focus on the user’s need and the expected behavior instead of getting caught up in implementation details.
- Evolutionary Design:
BDD embraces the fact that the product understanding is evolving and the needs are changing. It helps the developers to keep pace with changing goal.
- Greater ROI:
Behavior captures the change of business rules better since it has a longer shelf life than the implementation and documentation.
- Predictability & Confidence:
BDD gives the team members more confidence because they have a better understanding and evaluation of the requirement. This will improve the software development efficiency.
Advantages of Test-Driven Development
- Maintainable, Flexible, Easily Extensible<ref>benefits of test driven development</ref>
Since testing in TDD is integrated into the development process at the most granular level, it is guaranteed that every standalone piece of logic can be tested – and therefore changed – confidently. At the end of the application development, there exist thousands of test cases. When a change is made to the application, all that must be done is run the existing test cases to see if the change has adversely impacted any other piece of the application. This removes all roadblocks from updating legacy applications and making changes within the current development. This has clear benefits for young companies seeking rapid growth, older organizations who need to update legacy systems, and organizations who want to diversify service options or revenue channels.
- Unparalleled Test Coverage & Streamlined Codebase
In TDD, code is never written without first writing a test. This results in unprecedented test coverage. Further, the refactoring process ensures written code is as economical as possible, streamlining the codebase. If there is not a use-case for a piece of functionality, the test is never written – therefore, the codebase does not grow. This is the root of two main benefits of using TDD; it facilitates easy maintenance and helps alleviate scope creep.
- Clean Interface
Because programmers write the test first, the APIs they produce are naturally written from an API-user perspective. Resultantly, these APIs are far easier to use than those written by programmers more concerned with the internal workings of their packages.
- Refactoring Encourages Improvements
The refactoring process central to TDD ensures that developers constantly shore up the strength of the codebase. This prevents applications from growing dated and monolithic.
Difference
Behavior Driven Development is an extension/revision of Test Driven Development.BDD focuses on the behavioural aspect of the system rather than the implementation aspect of the system that TDD focuses on<ref>Difference between TDD and BDD</ref>. BDD gives a clearer understanding as to what the system should do from the perspective of the developer and the customer. TDD gives the developer an understanding of what the system should do.BDD BDD is more easily understood as design practice and not as testing practice.
Summary
See Also
- Test-driven development
- Behavior-driven_development
- Agile_software development
- Test-first development
Reference
<references></references>