views:

185

answers:

1

I'm just starting to practice BDD using the GWT approach to the following code exert and just realised that I can't do the second test.

My GWT goes something like

Given there exists an open query
When the user replies to the query
Then it should save the reply if the reply is not blank

Then it should notify the user and not save the reply if it is blank

So I coded it up like so

public class when_user_replies_to_the_query : OpenQuery
{
    Because
    {
         query.Reply(data);
    }

    ThenIt should_save_the_reply_to_the_database_if_there_is_a_reply

    ThenIt should_notify_the_user_if_there_is_no_text_in_the_reply_and_not_save_to_database
}

public class Query
{
    void Reply(string data)
    {
        //do something
    }
}

But then I realised that I can't do the second case because the first case requires data to have something in it whilst the second case says that data should be an empty string.

Does this mean that I should be splitting my GWT into something like

Given the reply is blank
When the user replies to the query
Then it should notify the user ......

If this is the case, then I'd be writing a huge amount of null case scenarios for return

values being null. Such as
Given the database is null
When retrieving queries
Should reply with error message
When saving queries
Should save to file and reply with error message
When // basically doing anything
Should //give appropriate response

Is this how I should be writing my BDD specs? And am I even in the right forum O_O?

+1  A: 

You would want to invert the two Then clauses, because they basically form different contexts under which the Query class is exercised. When you read both Then statemenents you can see that "if is not blank" and "is blank" form both contexts.

  1. Context #1:

    Given an open query
    Given a non-blank reply
    When the user replies to the query
    It should save the reply
    
    
    public class When_the_user_replies_to_the_query_and_the_reply_is_not_blank
    {
       static Query Query;
    
    
       Establish context = () =>
       {
           Query = new Query();
       };
    
    
       Because of = () =>
       {
           Query.Reply("answer");
       };
    
    
       It should_save_the_reply = () =>
       {
           // Use your imagination
       };
    }
    
  2. Context #2:

    Given an open query
    Given a blank reply
    When the user replies to the query
    It should not save the reply
    It should notify the user
    
    
    public class When_the_user_replies_to_the_query_and_the_reply_is_blank
    {
       static Query Query;
    
    
       Establish context = () =>
       {
           Query = new Query();
       };
    
    
       Because of = () =>
       {
           Query.Reply(String.Empty);
       };
    
    
       It should_not_save_the_reply = () =>
       {
           // Use your imagination
       };
    
    
       It should_notify_the_user = () =>
       {
           // Use your imagination
       };
    }
    

Considering that you could have multiple possible "empty reply" values (null, String.Empty, " ", \r\n) , you could write contexts for any of these. I often do not write specs for any imaginable combination of values, but rather

  • have one context for the "happy path", i.e. reply is not empty
  • have one context for empty replies

In the light of your example, one could argue that the Query class isn't the right place to decide whether a reply satisfies the "is not empty" specification. You should rather code up that decision in a separate class and the Query should rely on the decision of that one. This would bring some advantages:

  • Separation of concerns: the Query class and the specification can evolve separately
  • You can re-use the specification in multiple places, hinting a problem with the reply before the user posts his empty reply
  • You can get the specification under test separately without worrying about user notification and database saves, thus preventing context explosion for Query concerns
Alexander Groß