Seeking Conditions in TDL

Regarding my post on Seeking Requirements in TDL, a comment was made regarding the question of whether or not I was focusing on the conditions as part of the scenario and whether or not this tied into how I view requirements being made manifest in a test spec. The answer to both questions is “yes” but since that response may require a bit of elaboration, this post is my attempt at that.

Consider the Conditions

A test condition is a particular behavior with respect to certain circumstances. Consider a simple statement you might see in a programming language:

if (age < 21)

That's a condition. It's saying that what happens, or how something behaves, is conditional upon something. There are actually two types of condition we are considering here. The data condition is age. The test condition is whether the data condition (age) is less than a value (21).

So now let's consider my original examples (with elements bolded):

Scenario: No Discount For Active Customer
  GIVEN an Active customer
  WHEN  the customer makes a purchase less than $10.00
  THEN  no discount is applied
  WHEN  the customer makes a purchase of exactly $10.00
  THEN  no discount is applied

Scenario: Discount for Active Customer
  GIVEN an Active customer
  WHEN  the customer makes a purchase of $10.50
  THEN  a discount of 1% is applied

Here the bolded elements are, to me, indicating data and test conditions. Writing this out, I might have this:

if (purchase <= 10.00)
  discount = 0
else
  discount = 1

So here my data conditions are purchase and discount. The test conditions are whether purchase is less than or equal to (<=) the value of 10.00 or whether purchase is greater than the value of 10.00. The second test condition is implied with the 'else' clause above but if you want to see it called out:

if (purchase <= 10.00)
  discount = 0
else if (purchase > 10.00)
  discount = 1

The data condition of discount will either take the value 0% or 1% based on the above test conditions. So the bolded phrases from my scenarios are meant to indicate these type of test or data conditions. And, in fact, in doing this you can probably already see a change it would be nice to make.

Do you see what it might be?

I would say it is this: the $10.50 is not necessarily clear in terms of why it is $10.50. You might assume that it fits in with the previous scenario where we had "less than $10.00" and "exactly $10.00" wherein here we now have "greater than $10.00." And in fact that would be true. But still ... it was an assumption.

So really, the second scenario could -- and perhaps should -- be:

Scenario: Apply Discount for Active Customer
  GIVEN an Active customer
  WHEN  the customer makes a purchase of greater than $10.00
  THEN  a discount of 1% is applied

Specific Value or Generic Condition?

Does this put us into a potential testing issue? Specifically, if the value to be used is simply specified as "greater than $1000", then what value will the tester (whether manual or automated) use? Clearly it is up to the tester. That can be a good thing as different values being used in tests is a way to inject variation. If you wanted to call out specific values, then you could perhaps use a data table. I already had indicated this a bit in A TDL Communicates Intent and Describes Behavior.

What I hope I got across was the idea of making sure the conditions are clear. Each scenario is a essence a high level condition that states some of the key elements of my conditions. Again, consider the above as if written out in some form of code:

if (customer == "Active")
  if (purchase <= 10.00)
    discount = 0
  else if (purchase > 10.00)
    discount = 1

Here I've bolded the first instance of each condition term. Of those terms, the only one I'm missing from my scenario title is "purchase". If I really wanted to have my scenario state each condition, I could have done it like this:

Scenario: Apply Discount for Active Customer Purchases

However, I think the scenario title was fine even without the inclusion of the word purchases. I also think it's a good habit to avoid trying to include every possible condition term in your scenario title. After all, if your app is even slightly complex, you are probably going to have a hard time fitting everything within a single concise declarative statement.

Speaking of more complicated conditions, let's consider one that's only slightly more complicated. Let's say there's a general business rule that says "a 2% discount is applied when a purchase is greater than $10.00 but less than $25.00 and is a long-standing title."

Explicit Data

These are cases where, given the nature of the related conditions, you may want to spell out more data. It's all about what makes it clear. Let's consider the above business rule and write it as a scenario:

Scenario: Apply Discount for Mid-Range, Long-Standing Games
  GIVEN an Active customer
  AND   a $12.00 long-standing game
  WHEN  the customer purchases the game
  THEN  a discount of %2 is applied

So I called something a "mid-range, long-standing game." Just by looking at the scenario (and the steps), what does that mean? Forget the business rule you saw earlier. Just consider the scenario as written. What do I mean by "mid-range, long-standing game." You have absolutely no idea, right? Just by looking at the scenario (and the steps), why did I choose a value of $12.00? You really don't have a clue, do you?

This sort of circles back to making it clear what you are testing for. So how do you deal with that? Because this does get to the heart of how you know you are testing the requirement, right? Well, here's one idea:

Feature: Apply a Discount for Weekend Sale Purchases

  A "mid-range" game is one that costs between $10.00 and $25.00.
  A "long-standing" game is one that is over five years old and has had no sales in the past one year.
  
  Scenario: Apply Discount for Mid-Range, Long-Standing Games
    GIVEN an Active customer
    AND   a $12.00 long-standing game
    WHEN  the customer purchases the game
    THEN  a discount of %2 is applied

Or would it be better to word the context part of the scenario this way:

GIVEN an Active customer
AND   a long-standing game that costs between $10.00 and $25.00

Well, "a game that costs between $10.00 and $25.00" is a mid-range game, as we've already stated. The fact that it happens to be a long-standing game is a different aspect. So I could just say:

GIVEN an Active customer
AND   a mid-range, long-standing game

Here "mid-range game" is a valid data condition that refers to a domain phrase. In fact, the phrase has the data condition (purchase price) and the test condition (between $10.00 and $25.00) wrapped up in one phrase. When you add "long-standing" to it you have two more data conditions (age of game; sales) and two test conditions (greater than or equal to five years old; sales equal to zero for past year). Okay, but let's take a look at what we end up with assuming we make all these changes:

Feature: Apply a Discount for Weekend Sale Purchases

  A "mid-range" game is one that costs between $10.00 and $25.00.
  A "long-standing" game is one that is over five years old and has had no sales in the past one year.
  
  Scenario: Apply Discount for Mid-Range, Long-Standing Games
    GIVEN an Active customer
    AND   a mid-range, long-standing game
    WHEN  the customer purchases the game
    THEN  a discount of %2 is applied

Again, someone could say but you don't know if a tester is going to choose a game at $10.00 or at $25.00 or at some value in between. Technically that's fine since the behavior forms an equivalence class or any values in that range. Outside of that range, of course, is a different question -- and it's also a different scenario. Something less than $10.00 or greater than $25.00 is not a mid-range game and thus should not be dealt with in a scenario with mid-range game in the title.

Single Statement Business Rules

Before looking at another possible issue, I'll note you could actually just state this as a single clause:

Scenario: Apply Discount for Mid-Range, Long-Standing Games
  * a discount of 2% is applied when an Active customer purchases a mid-range, long-standing game

But, in either example, is my context (the AND clause in the first example or the last part of the asterisk example) duplicating too much of what I said in the scenario title? And, if so, is that bad? Well, you have a few options. One is simply do what I did above and not worry about it. The other is you could specify the data conditions and values as part of the steps, relying on the context of the scenario (along with the narrative at the top of the file) to make it clear what the data condition applies to.

Feature: Apply a Discount for Weekend Sale Purchases

  A "mid-range" game is one that costs between $10.00 and $25.00.
  A "long-standing" game is one that is over five years old and has had no sales in the past one year.
  
  Scenario: Apply Discount for Mid-Range, Long-Standing Games
    GIVEN an Active customer
    AND   a game that is greater than five years old
    AND   a game that has not had sales in the past year
    AND   a game that is between $10.00 and $25.00
    WHEN  the customer purchases the game
    THEN  a discount of %2 is applied

Is that good? Well, it can be fine but it makes the context wordy. You normally solve that by using domain phrases. So here we have a situation where we did define the domain phrase, but didn't use it. Which seems like a waste.

Another option is you could have specific data that you know you can rely on as part of your "gold data" that is used for testing. In that case, you might call out the specific data item:

Feature: Apply a Discount for Weekend Sale Purchases

  A "mid-range" game is one that costs between $10.00 and $25.00.
  A "long-standing" game is one that is over five years old and has had no sales in the past one year.
  
  Scenario: Apply Discount for Mid-Range, Long-Standing Games
    GIVEN an Active customer
    WHEN  the customer purchases the game "Midsummer Evening of Walking Living Dead"
    THEN  a discount of %2 is applied

From a step reusability standpoint, I like this one:

Scenario: Apply Discount for Mid-Range, Long-Standing Games
  * a discount of 2% is applied when an Active customer purchases a mid-range, long-standing game

Why? Because it states the business rule largely as a business user would. My matcher for these kinds of phrases could be something along these lines:

(/^a discount of (/d+)% is applied when an (.*) customer purchases a (.*) game$/)

Balance of Repetition and Duplication

But with my scenario title and my step statement, am I repeating a little, yes? Is that bad, I don't know. I try to avoid doing so but to a certain extent when you define your conditions with domain phrases there probably is going to be a little of that. Notice what my scenario title is not. It was not this:

Scenario: Apply a 2% Discount for Mid-Range, Long-Standing Games for Active Customers

That would be too much duplication for me. Beyond just the duplication concerns, this example includes a value (2%) in the title, which I think should be considered a no-no. Why did I not originally include the Active customer clause in the scenario title, though? That seems relevant, no? It does, but the operative conditions I'm testing for are "discount on item." The key action is "apply a discount." I don't apply a discount to a customer. I apply it to a product. This allows me to have different steps for different customers:

Scenario: Apply Discount for Mid-Range, Long-Standing Games
  * a discount of 2% is applied when an Active customer purchases a mid-range, long-standing game
  * a discount of 5% is applied when a Gamer customer purchases a mid-range, long-standing game

As far as the repetition goes, can I avoid that? Since the title already says "mid-range, long-standing games" can I just do this:

Scenario: Apply Discount for Mid-Range, Long-Standing Games
  * a discount of 2% is applied for an Active customer purchase
  * a discount of 5% is applied for a Gamer customer purchase

I could do that but, from an automated execution standpoint, that can become problematic. I say that because from an automated test perspective, the above phrases would not fully establish the context.

Before considering that issue, if in fact it even is an issue, also notice how I have two different data conditions being tested for. Should those instead be different scenarios? Based on what I just said above regarding the operative condition ("discount on item"), I would answer no. But if the answer was 'yes', then I would have to call out the customer as well in each scenario title:

  Scenario: Apply Discount for Mid-Range, Long-Standing Games for Active Customers
  Scenario: Apply Discount for Mid-Range, Long-Standing Games for Gamer Customers

Details and Duplication

Now let's go back to that other issue, in terms of how much detail is duplicated between the scenario title and the scenario steps. I ended up with two variations:

Variation 1

Scenario: Apply Discount for Mid-Range, Long-Standing Games
  * a discount of 2% is applied when an Active customer purchases a mid-range, long-standing game
  * a discount of 5% is applied when a Gamer customer purchases a mid-range, long-standing game

Variation 2

Scenario: Apply Discount for Mid-Range, Long-Standing Games
  * a discount of 2% is applied for an Active customer purchase
  * a discount of 5% is applied for a Gamer customer purchase

I think the level of detail in Variation 1 is what I want in the steps, assuming that I am using domain phrases and not specific values. Assuming I'm worried about the duplication of content (i.e., the "mid-rang, long-standing game" text), I could shorten the scenario title. Since I seem to be focusing on variation 1, here is what that might look like:

Scenario: Apply Discounts for Active Customer
  * a discount of 2% is applied when an Active customer purchases a mid-range, long-standing game
  * a discount of 5% is applied when a Gamer customer purchases a mid-range, long-standing game

With this, though, I'm potentially broadening out what the scenario can cover. After all, now the scenario title would be applicable to any discount that can be applied to an Active customer. Also notice that now my second condition -- "5% is applied when a Gamer customer" -- no longer applies to this scenario and would have to be removed. I suppose I could just make the scenario "Apply Discounts for Customers" but, now, of course it's becoming the equivalent of an 'epic' scenario in that it would have to cover all aspects of how discounts are applied to any customer.

Consider Scenario Breakdown

Notice how it's easy to keep bouncing around between one solution and another? When I encounter these situations it's usually telling me that I might want to consider using specific data values or specific data in my scenario steps. It's a time for me to question how I am breaking out my scenarios. It's also interesting to consider whether domain phrases ("mid-range, long-standing game") should be used solely in the scenario title and not in the scenario steps. But that gets interesting when one part of the phrase is easier to specify. Consider a whole feature example again:

Feature: Apply a Discount for Weekend Sale Purchases

  A "mid-range" game is one that costs between $10.00 and $25.00.
  A "long-standing" game is one that is over five years old and has had no sales in the past one year.
  
  Scenario: Apply Discount for Mid-Range, Long-Standing Games
    GIVEN an Active customer
    AND   a $12.00 long-standing game
    WHEN  the customer purchases the game
    THEN  a discount of %2 is applied

Here in my GIVEN, stating a specific data value for the domain phrase "mid-range game" is easy: I just specify a value between $10.00 and $25.00. But how do I state a specific value for the domain phrase a "long-standing game"? The only way I can do so is via recourse to the name of a specific game or by making the phrase even more unwieldy: "a game that is over five years old and has had no sales in the past one year." Further, the amount you are going to want to permute the data values will indicate how you want to call out details in your scenario title and your scenario steps.

What I hope this shows is that what I consider to be an effective TDL is one that uses scenario titles to convey the most relevant, or operative, elements of test conditions. That is usually how you will stick to conveying intent in your scenario title. Ideally these test conditions are stated as domain phrases where and when applicable. The scenario titles generally do not include the values of data conditions but they are likely to include the name of data conditions (i.e., "purchase" or "discount").

What you might notice, however, is that this is a hard area to provide prescriptive rules for. What is and is not "too much detail" for your scenarios will depend on your application, the complexity of the scenarios you are attempting to write up, and the skills of each individual person in determining how and when to write "just enough" information in the scenario title to convey intent about the type of condition being exercised by the scenario.

Share

This article was written by Jeff Nyman

Anything I put here is an approximation of the truth. You're getting a particular view of myself ... and it's the view I'm choosing to present to you. If you've never met me before in person, please realize I'm not the same in person as I am in writing. That's because I can only put part of myself down into words. If you have met me before in person then I'd ask you to consider that the view you've formed that way and the view you come to by reading what I say here may, in fact, both be true. I'd advise that you not automatically discard either viewpoint when they conflict or accept either as truth when they agree.

2 thoughts on “Seeking Conditions in TDL”

  1. Good stuff! Yeah, this gets confusing for me sometimes because I’m never sure if I’m providing too much detail or too little. One thing I know is that I don’t like a lot of repeating. But I see your point about the domain phrasing. If I use the domain phrase in the scenario title then it implies that I would use that same domain phrase in the steps but then of course I’m duplicating. On the other hand it would seem odd to me to not use the domain phrase since we all agreed which phrases to use. This is really interesting now that I think more about it. In looking at some of the scenarios that my team has created, we seem to be all over the board. I wonder how much this argues *against* the idea of steps that are always purely declarative? What do you think?

    1. I think this is where it becomes necessary to make sure everyone understands there are two levels of implementation to discuss: the implementation of tasks, which will use certain domain terminology, and there is the implementation of how to interact with interface widgets. Both of those are levels of implementation and may be more or less “imperative” sounding.

      I’m starting to realize it can become easy to get hung up on how declarative you “should” be. Also, declarative to me does not imply, for example, a lack of specific data conditions or test conditions.

      My thoughts are evolving on this as I’m currently on a project that has a complex series of algorithms that are applied in different contexts, depending upon what data conditions you have in place or put in place. I’m hoping to expand on these real-world examples at some point.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.