When doing BDD, must I first TDD each piece of cod

2020-07-17 07:29发布

问题:

I've been given a kata to work on over the weekend. Before starting it I really just wanted to gather some thoughts. I'm not looking for the solution, just some ideas on the best approach/practice.

From the conversation I had it would seem that I need to use a BDD --> ATDD (relate to scenarios in gherkin) --> TDD approach. I'm just looking to work out the best approach.

My current thinking is to

1) Create a specflow project and distill the user story into a gherkin.

2) Create the associated acceptance tests in the gherkin (the scenarios) using GWT syntax and thus generate my ATTD style tests in the [binding] class (right click 'generate').

3) Make the gherkin ATDD tests pass.

The conundrum I have is that the tests that link directly to the ATTD tests in my gherkin file don't give me low level enough testing.

So what do I do? do I write my high level ATDD tests and then before making them pass do I dig down deeper and just write pure TDD tests to design my lower level objects?

Yeah, I haven't worked out how to work in a totally BDD manner (pure style) yet so just wondered how I dig down. I appreciate that you should work incrementally and complete one test and pass but I feel I need to start at a high level ATDD test and then go deeper, so the higher level tests wont work until I make my low level code work, but to follow TDD I need to test that low level code and so I have already broken the principle of 1 unit test then pass then refactor.....

Hope someone understands how to tell me 'how' to approach this without actually doing it. But here is the problem as provided to me...(I appreciate if the tester sees this they may fail me for asking here , but its more important that I learn rather than get the job). Yes I know I'm MAD :-)

I'd also love to know if I should have a separate project for my pure TDD tests. What's the best project structure? I'm thinking 1 specflow project and a .test project and a class library and a console app for the runtime.

P.S. anyone that helps me with this has a favour owed to them from me. hug or charity donation. Or just the +1 on here i guess is what you really want :-/

Rock, Paper, Scissors

User Story Front
+--------------------------------------------------+
|                                                  |
|     Title: Waste an Hour Having Fun              |
|                                                  |
| As a frequent games player,                      |
| I'd like to play rock, paper, scissors           |
| so that I can spend an hour of my day having fun |
|                                                  |
| Acceptance Criteria                              |
|  - Can I play Player vs Computer?                |
|  - Can I play Computer vs Computer?              |
|  - Can I play a different game each time?        |
|                                                  |
+--------------------------------------------------+

User Story Back
+--------------------------------------------------+
|                                                  |
| Technical Constraints                            |
|                                                  |
| - Doesn't necessarily need a flashy GUI          |
|   (can be simple)                                |
| - Can use any modern language                    |
|                              |
| - Libs / external modules should only be used    |
|   for tests                                      |
| - Using best in industry practices               |
|                                                  |
+--------------------------------------------------+

Don't know the game? http://en.wikipedia.org/wiki/Rock-paper-scissors

I'd be looking for a scaled down version (think minimum viable product). No database (i.e. session stored), simple interface - 2 or 3 hours' worth of work (tops) would be perfectly reasonable. I'm not looking for a full blown thing, just a small thing well crafted. If this was Java and not .NET, and more back end oriented I would make do with a console app. Looking for unit tests and well factored code in C#. What I'm looking for is coders that happen to use C# ASP.Net MVC.

回答1:

It's possible to follow TDD strictly while doing BDD, but you don't have to, and I don't.

BDD says write acceptance tests and drive out the details with unit tests. So, after you write an acceptance test for a feature, you can either

  • write all the code needed to make the acceptance test pass (then refactor), or

  • think about what classes and such you'll need to make the acceptance test pass, TDD each of them (i.e. write unit tests for each of them, make those tests pass, and refactor), and then run the acceptance test to make sure it passes (and refactor).

Regardless of which of these two methods one follows, one test-drives requirements which don't merit their own acceptance tests by writing unit tests. However, the first method does NOT require going back and writing unit tests for every class created when implementing the acceptance test.

I use the first method, because

  • it's easier to think about. It doesn't require as much design up front, and it doesn't require context-switching between acceptance and unit tests.

  • it creates only the code needed to make the acceptance test pass. I invariably find that writing unit tests before (or without) acceptance leads to wrong guesses and extra code.

  • it doesn't test any requirements twice. Minimal test suites are faster and easier to maintain.

Advantages of the second method that I can see are

  • it breaks up the work needed to make the acceptance test pass. (But, with the tools I use and applications I work on, I don't usually have a problem just implementing the acceptance test in one go. If I do, I cut corners in the first pass and go back and fill them out in a second pass.)

  • there is always a unit test for every class, so it's easy to find a test to run to make sure you haven't broken a given class when you change it. (But you're going to have to find and run the relevant acceptance test(s) soon enough anyway.)

Regarding project structure, I always find that it's better to keep tests of all kinds in the same project, repository, etc. as the code. Out of sight, out of mind.



回答2:

Thoughts from the WordPress backend world [yes this is a thing]...

You're doing BDD! Actually, this dichotomy that you're discussing is in my opinion one of the main aspects of doing BDD. Generally speaking, acceptance tests are slower, more brittle, and less focused than unit tests. Often, something you're testing with a browser could be tested another way, say with an API test or a unit test. It's usually better to drive down your use of browser or end to end tests, and increase your use of unit tests. I like to think of acceptance tests as unit tests that haven't been re-factored yet.

I use Codeception [for WordPress / PHP] although my comments are framework agnostic. Codeception switches between browser based tests and unit test easily. One of the neat features of Codeception is that it has free form PHP acceptance tests that go a step beyond Gherkin [it also runs Gherkin]. So I can start out with acceptance tests that are way less formal and less complete than Gherkin scenarios. A lot of times it's just a bunch of comments or notes. [BTW: As a freelance small business developer, I have yet to see a single non-programmer who can tolerate Gherkin. Not one.] In DEVELOPMENT [as opposed to testing] I often find that when I start with acceptance tests, they start out kind of nebulous or half working. So I might start with a half made acceptance test that doesn't really do much, and as I try to make it into something, I focus on adding UNIT tests to the project.

In other words I use acceptance tests to kind of drive what unit test I am going to make next. Hopefully, at the end of a bunch of cycles, I either have a really good and simple acceptance test that is laser focused AND a lot more unit tests - or - ideally I completely eliminate the acceptance test and just have a bunch of fast unit tests. It sort of evaporates into a bunch of unit tests.

As for WHAT to test. If you're on a team, test everything. If you're working by yourself, do this: As the thought begins to form in your head as to what is supposed to happen, start making the unit test based on your half made thought. If you can eliminate some of the acceptance test, great! If the thought goes to completion, finish the test to make it a reality. Once the test is done, if you want to ramble on without making another test, fine. Keep going. Just keep the code simple and concise. You don't have to worry about coverage when you're working by yourself, it's just a tool. Do this over and over and soon you'll have a bunch of tests and a bunch of confidence in your code.