2
votes

These days I've read several articles about BDD to find what it is talking about. Now I get a basic understandings, but still not clear about the whole process.

The following is what I think to do in a BDD process:

  1. All the stakeholders(BA, customer, Dev, QA) are sitting together to discuss the requirements, and write the agreed features on story cards. Here I take a "user registeration" feature as example:

    As a user,
    I want to register on the system,
    so that I can use its services
    
  2. Create several scenarios in Given/When/Then format, and here is one of them:

    Scenario: user successfully register
        Given an register page
        And an un-registered user
        When the user fills username "Jeff" and password "123456"
        And click on "Register"
        Then the user can see a "Success" message
        And the user "Jeff" is created in the system
    
  3. Implement this scenario with some BDD testing framework, say cucumber-jvm, like:

    import cucumber.api.java.en.Given;
    
    public class Stepdefs {
        @Given("an register page")
        public void an_register_page throws Throwable {
            // ...
        }
        @Given("an un-registered user")
        public void an_register_page throws Throwable {
            // ...
        }
        // ...
    }
    

    for the steps one by one.

    But I soon find myself in trouble: there are pages, models, maybe databases need for this scenario, seems a lot of thing to do.

What should I do now?

What should I do now? Do I need to discuss this scenario with all the stakeholders? For BA/Customer/QA, I don't think they really care about the implementations, is it a good idea to discuss it with some other developers?

Suppose after I discuss it with some other developers, we agree to split it to several small parts. Can we make these small parts as "scenario"s with Scenario/Given/When/Then format as what we just did with cucumber-jvm, or can we use JUnit as we normally do in TDD?

1. If choose "cucumber-jvm", it seems a little heavy for small part
2. If choose JUnit, we need to involve more than one testing framework in a project
3. Is it the best if there is a single testing framework to do both things (not sure if there is)

Suppose I choose option 2, using JUnit for the small tasks

The following is what I will do after this decision:

  1. Now we create new small tests to drive implementations, like creating user in database, as we normally do in TDD. (red->green->refactoring). And we don't care the cucumber test Scenario: user successfully register (which is failed) for now, just leave it there. Right?

  2. We develop more small tests with JUnit, made them red -> green -> refactored. (And the imcomplete cucumber test is always failed)

  3. Until all the small tests are passed, we turn to the cucumber test Scenario: user successfully register. Completed it and make sure it turn green at last.

  4. Now develop another scenario, if it's easy, we can implement it just with cucumber, otherwise we will have to split it and write several jUnit test

There are definitely a lot of mis-understandings, even very basic ones. Because I don't find myself gain much value from BDD except the "discuss with all stakeholders" part.

Where is my mistake? Appreciate for any sugguestions!

2

2 Answers

2
votes
  1. Don't start with logging in; start with the thing that's different to the other systems out there. Why is someone logging in? Why do they want to use the service? Hard-code a user, pretend they're logged in, focus on the value.

  2. If you focus on UI details you tie yourself to the UI very strongly, and it makes the UI hard to change. Instead, look at what capabilities the system is delivering. I don't recommend using a login scenario anyway, but if I did, I'd expect it to look more like:

    Given Jeff isn't registered with the site
    When he registers with the username "Jeff" and password "123456"  
    Then his account creation should be confirmed  
    And he should be invited to log in for the first time.
    

    Look up "declarative vs. imperative" here to see more on this.

  3. If your UI is really in flux, try out the scenario manually until the UI has settled down a bit. It will be easier to automate then. As you move into more stable scenarios it will be better to automate first (TDD-style).

  4. What should you do now? Well, most people don't write class-level tests for the UI, so don't worry about it until you start driving out the controller and presenter layers. It's normally easier to have frameworks in the same language, but two different frameworks is fine. Cucumber / RSpec, JBehave / JUnit, SpecFlow / NUnit are pretty typical combinations. Do the smallest amount you need to get that first scenario working. It won't be much, because you can hard-code a lot of it. The second scenario will start introducing more interesting behaviour, and then you'll start to see your class-level tests emerge.

BTW, BDD started at a class level, so you can do the same thing with the classes; think of an example of how you might use it, write "Given, When, Then" in comments if your framework doesn't work that way already, and then fill in the gaps!

  1. Yes, your Cucumber scenario will be red throughout, until it isn't.

  2. Ideally you'll be making one last unit test and the Cucumber scenario pass at the same time, rather than just writing a bit of extra code. It's very satisfying to see it finally go green.

  3. The original point of BDD was to get rid of the word "test", since it causes people to think of things like TDD as being about testing. TDD's really about clean design; understanding the responsibilities and behaviour of your code, in the same way that scenarios help you understand the capabilities and behaviour of your system. It should be normal to write both system-level scenarios and class-level tests too.

You're already ahead of all the people who forget to discuss the scenarios before they start coding, though! The conversations with stakeholders are the most important part. You might get value out of including a tester in those conversations. Testers are very good at spotting scenarios that other people miss.

It looks like you're pretty much on the right track where the rest of the process is concerned. You might find some of the other BDD answers in my profile helpful for you too. Congrats and good luck!

2
votes

I think doing registration/sign_in first is a really good thing to do when you are learning the mechanics of doing BDD. Pretty much everyone understands why you would want to sign into a system, and everyone understands that the system has to know who you are before you can do this, so you have to register first.

Doing this simple task allows you to concentrate on a smaller subset of BDD. By narrowing your focus you can improve quality, whilst being aware that there is much more to learn a little later on.

To write your sign in scenarios you need to focus on two things:

  • writing scenarios
  • implementing step definitions

These are the basic mechanics of BDD, but they are only a small part of the overall process. Still I think you'd benefit from working on them because at the moment you are not executing the mechanics very well, which is to be expected because you are new to this.

When you write scenarios you should concentrate on 'what' you are doing and 'why' you are doing it. Scenarios have no need to know anything about 'how' you do things. Anything to do with filling in stuff, clicking on stuff etc. is a smell. When your scenarios only deal with the what and why they become much simpler.

Feature: Registration
  A pre-requistite for signing in, see sign_in.feature

  Scenario: Register
    Given I am a new user
    When I register
    Then I should be registered

Feature: Sign in
  Dependant on registration ...
  I want to sign in so I can have personalised content and ...

  Scenario: Sign in
    Given I am registered 
    When I sign in
    Then I should be signed in

You really don't much more than this to drive the development of a simple sign_in system. Once you have that running you can deal with some sad paths e.g.

Scenario: Sign in with bad password
  Given I am registered
  When I sign in with a bad password
  Then I should not be signed in
  And I should be told ...

If you implement things nicely this sad path scenario should be trivial to implement as all the infrastructure is already in place to sign in, all that is different is you are using a bad password.

You can see an example of this at https://github.com/diabolo/cuke_up. The way to use this example is follow the commit history, and in particular notice how I am using the extract_method refactor to take all the code out of the step definitions. Each method I extract is a tool to reused when writing subsequent scenarios. Making an effective set of tools is the key to productivity when implementing scenarios.

Nowadys sign_up is so simple because we can rely on a 3rd party library and their unit tests. This means we can get pretty good results without ever having to worry about the transition to our own code and doing bits of TDD. So for now there really is no need to think about TDD.

So long as you are aware that you are only doing a small subset of BDD, I think you can successfully use this approach to provide foundations for all the extra stuff you have to deal with when working with the things that differentiate your system from others.

To summarize, just focus on

  • writing simple scenarios
  • making your step definitions elegant
  • creating tools (extracted methods) that can be used in the next scenario you write

You have plenty of time to learn the other stuff, and it will be much easier if your basic mechanics are better developed.