Automated Acceptance Testing Best Practices

automated acceptance test driven development and automated acceptance test tools benefits and how to do acceptance testing, how to perform acceptance testing
Prof.WilliamsHibbs Profile Pic
Prof.WilliamsHibbs,United States,Teacher
Published Date:28-07-2017
Your Website URL(Optional)
Comment CHAPTER 1 Why Cucumber? Software starts as an idea. Let’s assume it’s a good idea—an idea that could make the world a better place, or at least make someone some money. The challenge of the software developer is to take the idea and make it real, into something that actually delivers that benefit. The original idea is perfect, beautiful. If the person who has the idea happens to be a talented software developer, then we might be in luck: the idea could be turned into working software without ever needing to be explained to anyone else. More often, though, the person with the original idea doesn’t have the necessary programming skill to make it real. Now the idea has to travel from that person’s mind into other people’s. It needs to be communicated. Most software projects involve teams of several people working collaboratively together, so high-quality communication is critical to their success. As you probably know, good communication isn’t just about eloquently describing your ideas to others; you also need to solicit feedback to ensure you’ve been understood correctly. This is why agile software teams have learned to work in small increments, using the software that’s built incrementally as the feedback that says to the stakeholders “Is this what you mean?” Even this is not enough. If the developers spend a two-week iteration imple- menting a misunderstanding, not only have they wasted two weeks of effort, but they’ve corrupted the integrity of the codebase with concepts and func- tionality that do not reflect the original idea. Other developers may have already innocently started to build more code on top of those bad ideas, making it unlikely they’ll ever completely disappear from the codebase. We need a kind of filter to protect our codebase from these misunderstood ideas. report erratum • discuss4 • Chapter 1. Why Cucumber? 1.1 Automated Acceptance Tests 1 The idea of automated acceptance tests originates in eXtreme Programming 2 (XP), specifically in the practice of Test-Driven Development (TDD). Instead of a business stakeholder passing requirements to the development team without much opportunity for feedback, the developer and stakeholder collaborate to write automated tests that express the outcome that the stakeholder wants. We call them acceptance tests because they express what the software needs to do in order for the stakeholder to find it acceptable. The test fails at the time of writing, because no code has been written yet, but it captures what the stakeholder cares about and gives everyone a clear signal as to what it will take to be done. These tests are different from unit tests, which are aimed at developers and help them to drive out and check their software designs. It’s sometimes said that unit tests ensure you build the thing right, while acceptance tests ensure you build the right thing. Automated acceptance testing has been an established practice among good XP teams for years, but many less experienced agile teams seem to see TDD as being a programmer activity only. As Lisa Crispin and Janet Gregory point out in Agile Testing: A Practical Guide for Testers and Agile Teams CG08, without the business-facing automated acceptance tests, it’s hard for the programmers to know which unit tests they need to write. Automated accep- tance tests help your team to focus, ensuring the work you do each iteration is the most valuable thing you could possibly be doing. You’ll still make mis- takes—but you’ll make a lot less of them—meaning you can go home on time and enjoy the rest of your life. 1.2 Behaviour-Driven Development 3 Behaviour-Driven Development (BDD) builds upon Test-Driven Development (TDD) by formalizing the good habits of the best TDD practitioners. The best TDD practitioners work from the outside-in, starting with a failing customer acceptance test that describes the behavior of the system from the customer’s point of view. As BDD practitioners, we take care to write the acceptance tests as examples that anyone on the team can read. We make use of the process of writing those examples to get feedback from the business stakeholders about whether we’re setting out to build the right thing before we get started. 1. Extreme Programming Explained: Embrace Change Bec00 2. Test Driven Development: By Example Bec02 3. report erratum • discussBehaviour-Driven Development • 5 As we do so, we make a deliberate effort to develop a shared, ubiquitous lan- guage for talking about the system. Ubiquitous language As Eric Evans describes in his book Domain Driven Design Eva03, many software projects suffer from low-quality communication between the domain experts and programmers on the team: “A project faces serious problems when its language is fractured. Domain experts use their jargon while technical team members have their own language tuned for discussing the domain in terms of design... Across this linguistic divide, the domain experts vaguely describe what they want. Developers, struggling to under- stand a domain new to them, vaguely understand.” With a conscious effort by the team, a ubiquitous language can emerge that is used and understood by everyone involved in the project. When the team uses this language consistently in their conversations, documentation, and code, the friction of translating between everyone’s different little dialects is gone, and the chances of misunderstandings are greatly reduced. Cucumber helps facilitate the discovery and use of a ubiquitous language within the team, by giving the two sides of the linguistic divide a place where they can meet. Cucumber tests interact directly with the developers’ code, but they’re written in a medium and language that business stakeholders can understand. By working together to write these tests—specifying collabo- ratively—not only do the team members decide what behavior they need to implement next, but they learn how to describe that behavior in a common language that everyone understands. When we write these tests before development starts, we can explore and eradicate many misunderstandings long before they ooze their way into the codebase. Examples What makes Cucumber stand out from the crowd of other testing tools is that it has been designed specifically to ensure the acceptance tests can easily be read—and written—by anyone on the team. This reveals the true value of acceptance tests: as a communication and collaboration tool. The easy read- ability of Cucumber tests draws business stakeholders into the process, helping you really explore and understand their requirements. Here’s an example of a Cucumber acceptance test: report erratum • discuss6 • Chapter 1. Why Cucumber? Feature:Signup Signupshouldbequickandfriendly. Scenario:Successfulsignup Newusersshouldgetaconfirmationemailandbegreeted personallybythesiteoncesignedin. GivenIhavechosentosignup WhenIsignupwithvaliddetails ThenIshouldreceiveaconfirmationemail AndIshouldseeapersonalizedgreetingmessage Scenario:Duplicateemail Wheresomeonetriestocreateanaccountforanemailaddress thatalreadyexists. GivenIhavechosentosignup ButIenteranemailaddressthathasalreadyregistered ThenIshouldbetoldthattheemailisalreadyregistered AndIshouldbeofferedtheoptiontorecovermypassword Notice how the test is specified as examples of the way we want the system to behave in particular scenarios. Using examples like this has an unexpect- edly powerful effect in enabling people to visualize the system before it has been built. Anyone on the team can read a test like this and tell you whether it reflects their understanding of what the system should do, and it may well spark their imagination into thinking of other scenarios that you’ll need to consider too. Gojko Adzic’s book Specification by Example Adz11 contains many case studies of teams who have discovered this and used it to their advantage. Acceptance tests written in this style become more than just tests; they are executable specifications. 1.3 Living Documentation Cucumber tests share the benefit of traditional specification documents in that they can be written and read by business stakeholders, but they have a distinct advantage in that you can give them to a computer at any time to tell you how accurate they are. In practice, this means that your documentation, rather than being something that’s written once and then gradually goes out of date, becomes a living thing that reflects the true state of the project. report erratum • discussHow Cucumber Works • 7 Source of Truth For many teams, they become the definitive source of truth as to what the system does. Having a single place to go for this information saves a lot of time that is often wasted trying to keep requirements documents, tests, and code all in sync. It also helps to build trust within the team, because different parts of the team no longer have their own personal versions of the truth. 1.4 How Cucumber Works Before we dive into the meat of the book, let’s give you some context with a high-level overview of a typical Cucumber test suite. Cucumber is a command-line tool. When you run it, it reads in your specifi- cations from plain-language text files called features, examines them for scenarios to test, and runs the scenarios against your system. Each scenario is a list of steps for Cucumber to work through. So that Cucumber can under- stand these feature files, they must follow some basic syntax rules. The name for this set of rules is Gherkin. Along with the features, you give Cucumber a set of step definitions, which map the business-readable language of each step into Ruby code to carry out whatever action is being described by the step. In a mature test suite, the step definition itself will probably just be one or two lines of Ruby that delegate to a library of support code, specific to the domain of your application, that knows how to carry out common tasks on the system. Normally that will involve using an automation library, like the browser automation library Capybara, to interact with the system itself. This hierarchy, from features down to automation library, is illustrated by Figure 1, Cucumber testing stack, on page 8. If the Ruby code in the step definition executes without error, Cucumber proceeds to the next step in the scenario. If it gets to the end of the scenario without any of the steps raising an error, it marks the scenario as having passed. If any of the steps in the scenario fail, however, Cucumber marks the scenario as having failed and moves on to the next one. As the scenarios run, Cucumber prints out the results showing you exactly what is working and what isn’t. That’s it in a nutshell. There are many other advantages to Cucumber that make it an excellent choice: you can write your specifications in more than forty different spoken languages, you can use tags to organize and group your scenarios, and you can easily integrate with a host of high-quality Ruby report erratum • discuss8 • Chapter 1. Why Cucumber? Your Project Features Business Scenarios Facing Steps Step Definitions Technology Support Code Facing Automation Library Your System Figure 1—Cucumber testing stack automation libraries to drive almost any kind of application. All that and more will become clear as you read the rest of the book. 1.5 What We Just Learned Let’s review what we’ve covered so far. Software teams work best when the developers and business stakeholders are communicating clearly with one another. A great way to do that is to collaboratively specify the work that’s about to be done using automated acceptance tests. When the acceptance tests are written as examples, they stimulate people’s imaginations and help them see other scenarios they hadn’t previously considered. When the team write their acceptance tests collaboratively, they can develop their own ubiquitous language for talking about their problem domain. This helps them avoid misunderstandings. report erratum • discussWhat We Just Learned • 9 Cucumber was designed specifically to help business stakeholders get involved in writing acceptance tests. Each test case in Cucumber is called a scenario, and scenarios are grouped into features. Each scenario contains several steps. The business-facing parts of a Cucumber test suite, stored in feature files, must be written according to syntax rules—known as Gherkin—so that Cucumber can read them. Under the hood, step definitions translate from the business-facing language of steps into Ruby code. To illustrate these concepts, in the next chapter we’re going to dive right in and build a very simple application, using Cucumber to drive the development. Try This Cucumber has its own ubiquitous language. Can you list the terms about Cucumber’s domain you’ve learned in this chapter and describe what you think each of them means? report erratum • discussCHAPTER 2 First Taste We figured you’d be eager to start playing with your shiny new toy right away, so we’re going to work through a simple example that will give you a feel for what it’s like to work with Cucumber. You might not quite understand every- thing that happens here just yet, but try not to let that worry you. We’ll come back and fill in the details over the next few chapters. We’re going to build a simple command-line application from the outside-in, driving our development with Cucumber. Watch how we proceed in very small baby steps, going back to run Cucumber after we make each change. This patient rhythm is an important characteristic of working effectively with Cucumber, but it’s much easier to demonstrate than to explain. Assuming you want to follow along with the action in this chapter (it’ll be a lot more fun if you do), you’ll need to have Cucumber installed. If you haven’t already done so, see Appendix 2, Installing Cucumber, on page 299 for installa- tion instructions. Right...shall we get started then? 2.1 Understanding Our Goal Our goal is to write a program that can perform calculations. Some people might call it a calculator. We have an incredible vision of what this calculator will one day become: a cloud-based service that runs on mobile phones, desktops, and browsers, uniting the world with the opportunity of ubiquitous mathematical operations. We’re pragmatic businesspeople, though, so the first release of our program has to be as simple as possible. The first release will be a command-line program, implemented as a Ruby script. It will take input containing the calculation to be done and display the result at the command prompt. report erratum • discuss12 • Chapter 2. First Taste So, for example, if the input file looks like this: 2+2 then the output would be 4. Similarly, if the input file looks like this: 100/2 then the output would be 50. You get the idea. 2.2 Creating a Feature Cucumber tests are grouped into features. We use this name because we want them to describe the features that a user will be able to enjoy when using our program. The first thing we need to do is make a directory where we’ll store our new program along with the features we’ll be writing for it. mkdircalculator cdcalculator We’re going to let Cucumber guide us through the development of our calcu- lator program, so let’s start right away by running cucumber in this empty folder: cucumber Youdon'thavea'features'directory.Pleasecreateonetogetstarted. See Since we didn’t specify any command-line arguments, Cucumber has assumed that we’re using the conventional features folder to store our tests. That would be fine, except that we don’t have one yet. Let’s follow the convention and create a features directory: mkdirfeatures Now run Cucumber again. cucumber 0scenarios 0steps 0m0.000s Each Cucumber test is called a scenario, and each scenario contains steps that tell Cucumber what to do. This output means that Cucumber is happily report erratum • discussCreating a Feature • 13 scanning the features directory now, but it didn’t find any scenarios to run. Let’s create one. Our user research has shown us 67 percent of all mathematical operations are additions, so that’s the operation we want to support first. In your favorite editor, create a plain-text file called features/adding.feature: Download first_taste/01/features/adding.feature Feature:Adding Scenario:Addtwonumbers Giventheinput"2+2" Whenthecalculatorisrun Thentheoutputshouldbe"4" This .feature file contains the first scenario for our calculator program. We’ve translated one of the examples we were given in the previous section into a Cucumber scenario that we can ask the computer to run over and over again. You can probably see that Cucumber expects a little bit of structure in this file. The keywords Feature, Scenario, Given, When, and Then are the structure, and everything else is documentation. Although some of the keywords are highlighted here in the book—and they may be in your editor too—it’s just a plain-text file. The structure is called Gherkin. When you save this file and run cucumber, you should see a great deal more output than the last time: cucumber Feature:Adding Scenario:Addtwonumbers Giventheinput"2+2" Whenthecalculatorisrun Thentheoutputshouldbe"4" 1scenario(1undefined) 3steps(3undefined) 0m0.003s Youcanimplementstepdefinitionsforundefinedstepswiththesesnippets: Given/theinput"(")"/doarg1 pendingexpresstheregexpabovewiththecodeyouwishyouhad end When/thecalculatorisrun/do pendingexpresstheregexpabovewiththecodeyouwishyouhad end report erratum • discuss14 • Chapter 2. First Taste Then/theoutputshouldbe"(")"/doarg1 pendingexpresstheregexpabovewiththecodeyouwishyouhad end Ifyouwantsnippetsinadifferentprogramminglanguage, justmakesureafilewiththeappropriatefileextension existswherecucumberlooksforstepdefinitions. Wow, that’s a lot of output all of a sudden Let’s take a look at what’s going on here. First, we can see that Cucumber has found our feature and is trying to run it. We can tell this because Cucumber has repeated the content of the feature back to us. You might also have noticed that the summary output 0 scenarios has changed to 1scenario(undefined). This means that Cucumber has read the scenario in our feature but doesn’t know how to run it yet. Second, Cucumber has printed out three code snippets. These are sample code for step definitions, written in Ruby, which tell Cucumber how to translate the plain English steps in the feature into actions against our application. Our next step will be to put these snippets into a Ruby file where we can start to flesh them out. Before we explore beneath the layer of business-facing Gherkin features into step definitions, it’s worth taking a quick look at the map in case anyone is feeling lost. Figure 2, The main layers of a Cucumber test suite, on page 15 reminds us how things fit together. We start with features, which contain our scenarios and steps. The steps of our scenarios call step definitions that provide the link between the Gherkin features and the application being built. Now we’ll implement some step definitions so that our scenario is no longer undefined. 2.3 Creating Step Definitions Without thinking too much about what they mean, let’s just copy and paste the snippets from Cucumber’s last output into a Ruby file. Just like the fea- tures, Cucumber is expecting the step definitions to be found in a conventional place: mkdirfeatures/step_definitions Now create a Ruby file in features/step_definitions, called calculator_steps.rb. Cucumber won’t mind what you call it as long as it’s a Ruby file, but this is a good name to use. Open it in your text editor and paste in those snippets: report erratum • discussCreating Step Definitions • 15 Features (Gherkin) (Ruby) Your App Figure 2—The main layers of a Cucumber test suite Download first_taste/02/features/step_definitions/calculator_steps.rb Given/theinput"(")"/doarg1 pendingexpresstheregexpabovewiththecodeyouwishyouhad end When/thecalculatorisrun/do pendingexpresstheregexpabovewiththecodeyouwishyouhad end Then/theoutputshouldbe"(")"/doarg1 pendingexpresstheregexpabovewiththecodeyouwishyouhad end Running cucumber will tell us what to do next: Feature:Adding Scenario:Addtwonumbers Giventheinput"2+2" TODO(Cucumber::Pending) ./features/step_definitions/calculator_steps.rb:2 features/adding.feature:4 Whenthecalculatorisrun Thentheoutputshouldbe"4" 1scenario(1pending) 3steps(2skipped,1pending) 0m0.002s report erratum • discuss16 • Chapter 2. First Taste The scenario has graduated from undefined to pending. This is good news, because it means Cucumber is now running the first step, but as it did so, it hit the call to pending inside our copied-and-pasted step definition code, which tells Cucumber that this scenario is still a work in progress. We need to replace that pending marker with a real implementation. Notice that Cucumber reports the two other steps as skipped. As soon as it encounters a failed or pending step, Cucumber will stop running the scenario and skip the remaining steps. Let’s implement the first step definition. 2.4 Implementing Our First Step Definition We’ve decided this first release of our calculator is going to take its input from the user as a command-line argument, so our job in the step definition for Giventheinput"2+2" is just to remember the input so that we know what to pass on the command line when we run the calculator in the next step. In the features/step_definitions folder, edit the calculator_steps.rb file so that the first step definition looks like this: Download first_taste/03/features/step_definitions/calculator_steps.rb Given/theinput"(")"/doinput input=input end All we’ve done here is store the input from the feature in a Ruby instance variable. That instance variable will be around for as long as this particular scenario is running, so we can use it again in the next step when we actually run the calculator. Great, that was easy. Now, where were we again? Let’s ask cucumber: Feature:Adding Scenario:Addtwonumbers Giventheinput"2+2" Whenthecalculatorisrun TODO(Cucumber::Pending) ./features/step_definitions/calculator_steps.rb:9 features/adding.feature:5 Thentheoutputshouldbe"4" 1scenario(1pending) 3steps(1skipped,1pending,1passed) 0m0.002s report erratum • discussRunning Our Program • 17 Yay Our first step passed The scenario is still marked as pending, of course, because we still have the other two steps to implement, but we’re starting to get somewhere. 2.5 Running Our Program To implement the next step, edit features/step_definitions/calculator_steps.rb so that the second step definition looks like this: Download first_taste/04/features/step_definitions/calculator_steps.rb When/thecalculatorisrun/do output=`rubycalc.rbinput` raise('Commandfailed')unless?.success? end This code attempts to run our calculator program calc.rb, passing it the input we stored in the first step and storing any output in another instance variable. Then it checks a specially—but rather cryptically—named Ruby variable ? to check whether the command succeeded and raises an error if it didn’t. Remember that Cucumber fails a step if the step definition raises an error; this is the simplest way to do it. This time when we run Cucumber, we should see that it has actually tried to run our calculator: Feature:Adding Scenario:Addtwonumbers Giventheinput"2+2" ruby:Nosuchfileordirectorycalc.rb(LoadError) Whenthecalculatorisrun Commandfailed(RuntimeError) ./features/step_definitions/calculator_steps.rb:10 features/adding.feature:5 Thentheoutputshouldbe"4" FailingScenarios: cucumberfeatures/adding.feature:3 1scenario(1failed) 3steps(1failed,1skipped,1passed) 0m0.027s Our step is failing, because we don’t have a calc.rb program to run yet. You should see that Cucumber has highlighted the output from our raised error in red just beneath the step, helping you spot the problem. You might well think it’s a bit odd that we’ve written and run code that tries to run our calc.rb program, knowing perfectly well that the file doesn’t even report erratum • discuss18 • Chapter 2. First Taste exist yet. We do this deliberately, because we want to make sure we have a fully functioning test in place before we drop down to working on the solution. Having the discipline to do this means we can trust our tests, because we’ve seen them fail, and this gives us confidence that when the tests pass, we’re really done. This gentle rhythm is a big part of what we call outside-in devel- opment, and while it might seem strange at first, we hope to show you throughout the book that it has some great benefits. Another benefit of working from the outside-in is that we’ve had a chance to think about the command-line interface to our calculator from the point of view of a user, without having made any effort to implement it yet. At this stage, if we realize there’s something we don’t like about the interface, it’s very easy for us to change it. 2.6 Changing Formatters We think it’s starting to get distracting looking at the whole content of the feature in Cucumber’s output each time we run. Let’s switch to the progress formatter to get a more focused output. Run this command: cucumberformatprogress You should see the following output: .ruby:Nosuchfileordirectorycalc.rb(LoadError) F- (::)failedsteps(::) Commandfailed(RuntimeError) ./features/step_definitions/calculator_steps.rb:10 features/adding.feature:5 FailingScenarios: cucumberfeatures/adding.feature:3Scenario:Addtwonumbers 1scenario(1failed) 3steps(1failed,1skipped,1passed) 0m0.023s Instead of printing the whole feature, the progress formatter has printed three characters in the output, one for each step. The first . character means the step passed. The F character means the second step, as we know, has failed. The final - character means that the last step has been skipped. Cucumber has several different formatters that you can use to produce different types of output as your features run; you’ll learn more about them through the course of the book. report erratum • discussAdding an Assertion • 19 Formatters Cucumber formatters allow you to visualize the output from your test run in different ways. There are formatters that produce HTML reports, formatters that produce JUnit XML for continuous integration servers like Jenkins, and many more. Use cucumberhelp to see the different formatters that are available and try some out for yourself. We’ll explain more about formatters in Chapter 11, The Cucumber Com- mand-Line Interface, on page 191. That was an interesting little diversion, but let’s get back to work. We have a failing test to fix 2.7 Adding an Assertion So, following Cucumber’s lead, we need to create a Ruby file for our program. Let’s just create an empty Ruby file for the time being so that we can stay on the outside and get the test finished before we go on to the solution. Linux/ Mac users can type this to create an empty file: touchcalc.rb If you’re using Windows, there is no touch command, so either just create an empty text file named calc.rb in your editor or use this little trick: C:\echo.calc.rb When we run cucumber again, we should see that the second step is passing and we’re on to the final step: cucumberformatprogress ..P (::)pendingsteps(::) features/adding.feature:6:in‘Thentheoutputshouldbe"4"’ 1scenario(1pending) 3steps(1pending,2passed) 0m0.460s To get the last step definition working, change the last step definition in features/step_definitions/calculator_steps.rb to look like this: Download first_taste/07/features/step_definitions/calculator_steps.rb Then/theoutputshouldbe"(")"/doexpected_output output.should==expected_output end report erratum • discuss20 • Chapter 2. First Taste 1 We’re using an RSpec assertion to check that the expected output specified in the feature matches the output from our program that we stored in output in the previous step definition. If it doesn’t, RSpec will raise an error just like we did using raise in the last step definition. Now when we run cucumber, we have ourselves a genuine failing test: cucumberformatprogress ..F (::)failedsteps(::) expected:"4" got:""(using==)(RSpec::Expectations::ExpectationNotMetError) ./features/step_definitions/calculator_steps.rb:16 features/adding.feature:6 FailingScenarios: cucumberfeatures/adding.feature:3Scenario:Addtwonumbers 1scenario(1failed) 3steps(1failed,2passed) 0m0.587s Great Now our test is failing for exactly the right reason: it’s running our program, examining the output, and telling us just what the output should look like. This is a natural point to pause for a break. We’ve done the hard work for this release: when we come back to this code, Cucumber will be telling us exactly what we need to do to our program to make it work. If only all our requirements came ready-rolled with a failing test like this, building software would be easy Try This Can you write an implementation of calc.rb that makes the scenario pass? Remember at this stage, we have only a single scenario to satisfy, so you might be able to get away with quite a simple solution. We’ll show you our solution in the next section. 2.8 Making It Pass So, now that we have our solid failing Cucumber scenario in place, it’s time to let that scenario drive out a solution. 1. The RSpec Book CADH09 report erratum • discussMaking It Pass • 21 Joe asks: I Feel Weird: You’re Making Tests Pass but Nothing Works We’ve implemented a step that calls the calculator program and passes, even though the “program” is just an empty file. What’s going on here? Remember that a step isn’t a test in itself. The test is the whole scenario, and that isn’t going to pass until all of its steps do. By the time we’ve implemented all of the step definitions, there’s only going to be one way to make the whole scenario pass, and that’s to build a calculator that can perform additions When we work outside-in like this, we often use temporary stubs like the empty cal- culator program as placeholders for details we need to fill in later. We know that we can’t get away with leaving that as an empty file forever, because eventually Cucumber is going to tell us to come back and make it do something useful in order to get the whole scenario to pass. This principle, deliberately doing the minimum useful work the tests will let us get away with, might seem lazy, but in fact it’s a discipline. It ensures that we make our tests thorough: if the test doesn’t drive us to write the right thing, then we need a better test. There is a very simple solution that will make the test pass, but it’s not going to get us very far. Let’s try it anyway, for fun: Download first_taste/08/calc.rb print"4" Try it. You should see the scenario pass at last: ... 1scenario(1passed) 3steps(3passed) 0m0.479s Hooray So, what’s wrong with this solution? After all, we already said that we want to do the minimum work that the tests will let us get away with, right? Actually, that’s not quite what we said. We said we want to do the minimum useful work that the tests will let us get away with. What we’ve done here might have made the test pass, but it isn’t very useful. Apart from the fact that it certainly isn’t going to function as a calculator yet, let’s look at what we’ve missed out on testing with our smarty-pants one-liner solution: report erratum • discuss22 • Chapter 2. First Taste • We haven’t tried to read the input from the command line. • We haven’t tried to add anything up. In Crystal Clear: A Human-Powered Methodology for Small Teams Coc04, Alistair Cockburn advocates building a walking skeleton as early as possible in a project to try to flush out any potential problems with your technology choices. Obviously, our calculator is trivially simple, but it’s still worth con- sidering this principle: why don’t we build something more useful that passes this scenario and helps us learn more about our planned implementation? If you’re unconvinced by that argument, try looking at it as a problem of duplication. We have a hard-coded value of 4 in two places: once in our sce- nario and once in our calculator program. In a more complex system, this kind of duplication might go unnoticed, and we’d have a brittle scenario. Let’s force ourselves to fix this, using what Kent Beck calls triangulation (Test Driven Development: By Example Bec02). We’ll add another scenario to our feature, using a new keyword called a ScenarioOutline: Download first_taste/09/features/adding.feature Feature:Adding ScenarioOutline:Addtwonumbers Giventheinput"input" Whenthecalculatorisrun Thentheoutputshouldbe"output" Examples: inputoutput 2+24 98+199 We’ve turned our scenario into a ScenarioOutline, which lets us specify multiple scenarios using a table. We could have copied and pasted the whole scenario and just changed the values, but we think this is a more readable way of expressing the examples, and we want to give you a taste of what’s possible with Gherkin’s syntax. Let’s see what the output looks like now: cucumber Feature:Adding ScenarioOutline:Addtwonumbers Giventheinput"input" Whenthecalculatorisrun Thentheoutputshouldbe"output" Examples: report erratum • discuss

Advise: Why You Wasting Money in Costly SEO Tools, Use World's Best Free SEO Tool Ubersuggest.