Showing posts with label TDD. Show all posts
Showing posts with label TDD. Show all posts

Extend MSTest : TestCaseSource aka runtime inputs for test cases


Extending MSTest


Read this great post first by William Kempf. And It's true!

 http://www.digitaltapestry.net/blog/extending-mstest

 Next if you're willing to bear with all that, these are the only 2 posts from circa-2009 on the intertubes that give you any hope

MSDN Blogs - Bruce Taimana Part 1. Part 2
 

Writing an extension in 2013

The details have changed since 2009 and combined with the paucity of information, it was three days before I had something to show.

So my target extension was going to bring in NUnit's TestCaseSource functionality, whereby you could supply the parameters for a parameterized test via a method (at runtime. Compile-time is already supported via XML and DBs.. though cumbersome.)
[TestMethod] 
[TestCaseSource("DivideCases")]
public void MultipleParams(int n, int d, int q)
{
   Assert.AreEqual( q, n / d );
}

public static object[] DivideCases()
{
   return new[] 
   {
       new object[] {12, 3, 4},
       new object[] {12, 2, 6},
       new object[] {12, 4, 3}
   };
}

NUnit vs MSTest - 2011 Edition

I have tried to be as objective as possible. Disclaimer: NUnit user since 2005-06.

Legend:
  • MSTest as an alias for the unit-testing fwk bunded with VS2010 v10.0.30319 throughout this post (although technically it is the just the runner). It's much easier to say than VisualStudio QualityTools UnitTestFramework. For NUnit, I'm using v2.5.9
  • Class-Setup/Teardown - to be executed ONCE before/after ALL tests
  • Test-Setup/Teardown - to be executed before/after EVERY test

Major Differences
Migrating a test suite between the two runners might be non-trivial depending on your test code. MSTest and NUnit are very different in the way they go about running a set of tests. e.g. Consider a set of 2 classes containing tests - Class A with 2 tests, B with just one. If I insert logging at some critical points.. (I am looking at the default behavior - no customization)

String Calculator Kata : My first screencast trilogy

This is my attempt at Roy Osherove's popular String Calculator Katas. 


TDD StringCalculator Kata - Part1 from Gishu Pillai on Vimeo.



The Vimeo Album containing all 3 parts.

I'm using C# (VS2010+Resharper), NUnit and an IDE extension called Beacons 
(the wiki might be a bit behind the downloads tab :))


The videos look best when you have the HD option turned on and Scaling (hover on the video - top-right) turned off.
intermediate practitioners
For best results : download the videos and the subtitles. Use your media player with audio turned off and subtitles enabled at 2-4X. 
I don't do this (ever) so wasn't equipped with the proper audio gear (and coupled with the fact that I do not have an internet voice and can't code and speak at the same time, the audio is passable.)

beginners
Practice it a couple of times before watching. You'll get more out of it.


What I learned from it:
  • I need to practice more :) 
  • 2 modes of learning in a Kata 
    • muscle memory - goal: Speed. 
    • exploration - goal: Possible solutions. Take different choices and see how it ends up.
  • Automated refactoring (e.g. Resharper for C#) rules. Knowing your IDE and keyboard shortcuts goes a long way w.r.t. productivity
  • Streamline all routine work and bind them to keyboard shortcuts - like building, running tests, reusable code snippets/templates, etc
For people looking for screencasting tools on windows, I'd recommend
  1. BB Flashback Express - the free edition for screencasting. Export to AVI using ffdshow worked great for me.
  2. ShowOff - for highlighting keystrokes and chords. Keyboard Jedi wasn't too great with 64bit & keyboard chords (before my patience ran out).
 

Flash Cards Kata and the transformation priority premise

I began the new year by resolving to complete the PCL (Peter Siebel's) book. Around the same time, another interesting post by Uncle Bob appeared on the WWW. A discussion on the TDD yahoogroups spurred me to try a Kata - two-sided Flash Cards.

Looked easy enough to test my new-found Lisp skills. Although I was not consciously choosing the next test / step based on the transformation priority, I was curious to know if I had been doing it all along without knowing it.

This innocuous looking kata had me stuck initially - what is the right first step? Trash-canned the first couple of attempts. The third attempt was slow but I succeeded. I did it again in C# just to see if the language had any bearing on my method. This time I was faster because I was familiar with the trail now.

  1. I am not wiser with regard to the priority premise - I found I used a bunch of transformations that were not part (bold) of the original list (shown in blue below). As a result, their priorities are unknown. This was the proverbial rain on my parade.
  2. Also in the C# variant, I found a couple of tests where I needed multiple transformations to get to the next green & I could not figure out a smaller test.
Note: Check the "speaker notes" in case things get dense especially with the Lisp one. Use the menu button at the bottom-right to get to the presentation link

Attempt#1 Flash Cards Kata in Lisp


TEST User should be asked a question
  • {} => statement
TEST A right ans should be confirmed
  • P5 (statement->statements) adding more unconditional statements.
TEST A wrong ans should be corrected
  • P6 (unconditional->if) splitting the execution path
TEST Diff card and a right ans
  • P4 (constant->scalar) replacing a constant with a variable or an argument
TEST Diff card and a wrong ans
  • constant => expr
TEST Multiple cards
  • {} => loop (statement)
TEST Answers are case insensitive
  • exprX => exprY
TEST Answers can have leading/trailing whitespace
  • value => expr
Attempt#2 Flash Cards Kata in C#
TEST User is asked the question
  • P2 nil -> constant
TEST User is asked another question (triangulate)
  • {} => statement *** Play()
  • constant => field *** LastQuestionAsked
  • void => statement *** Ask() - is there a smaller step here?
TEST A correct ans is confirmed
  • P2 nil -> constant
TEST A wrong ans is corrected
  • P5 (unconditional->if) splitting the execution path *** Play()
  • P4 (statement->statements) adding more unconditional statements
  • nil => expr *** User.WhoAnswers
  • field assignment *** User.ctor
  • constant => field *** User.LastConfirmationReceived
  • void => statement *** User.Notify
TEST A diff question and a right answer
  • P4 constant => scalar arg
TEST A diff question and a wrong ans
  • constant => expression
TEST Two cards
  • {} => statements
TEST Multiple cards
  • {} => loop
  • P4 (statement->statements) adding more unconditional statements *** User
  • field assignment *** User.ctor
TEST Case insensitive answers
  • exprX => exprY
TEST Trim leading/trailing spaces
  • value => expr

Beacons - a VS 2010 Extension for TDD

Just uploaded an early version of a TDD visualization extension that I've been working on in my free time. Get an early version of Beacons from the google code project here


The extension only works with NUnit currently. You specify a file path to your NUnit test results file path (which is normally a TestResults.xml file in your .dll/.nunit folder) and you're all set to go.
It can't listen to Resharper test-runner yet. (yet.. if I can figure out how to tap in, should be not an issue.)


To see it in action, check out this video - switch to fullscreen HD


TDD StringCalculator Kata - Part1 from Gishu Pillai on Vimeo.
  • Shift+Alt+B, H - Change hats (adding behavior hat OR refactoring hat)
  • Shift+Alt+B, P - Play/Pause (when you need to take a break)
If you give it a fair try, I'd love to hear from you. Particularly I'm interested in finding patterns (so share end-of-session screenshots)
More ideas, comments, suggestions - feedback of any kind is welcome.. Post away at http://groups.google.com/group/beacons-tdd

Review : Growing Object Oriented Software - Guided by Tests: Freeman, Pryce

Recommended... best book on TDD in a while.

Just finished this one today... I got to fess up - that I am a "classicist". I've seen some real spaghetti tests involving mocks.. But I've gotten some periodic tension from the people on the other side of this religious fence of TDD. Since this book comes from "the torch-bearers of the mockist camp", I picked up a copy and tried to keep an open mind. And I although I haven't switched camps.. I now see the light. There is no one right path but the authors have placed some industrial strength beacons on this path and teach you how to use mocks and interaction tests to "grow" applications driven by automated tests. (However I still maintain that in untrained hands, Mocks (like C++) can be very dangerous and quickly lead into tarpits. Easy to abuse. However in the right hands, they can be used to write very expressive code & enable rapid and iterative development. ).

Some of the key takeaways for me were:
  • Developing outside-in ATDD: writing a 'walking skeleton' first , spotting objects and roles (relationships) between them, TDDing these objects and "folding them back" into a running app was a new method to me.
  • Listening to the tests, Focus on readability, tests with helpful diagnostics / failure messages, eliminating or reducing the irrelevant part of the test, use of builders + drivers to keep the tests concise
  • The chapters on threads and asynchronous testing are home-runs. Don't leave for work without it. The last third of the book was worth the price of the book (It isn't yet available in India so had to get it from overseas).
There is a lot of real world knowledge that the authors have distilled down to a kind of 'secret sauce'.

MergeSort in Ruby

Finally got the ball rolling on the 'Introduction to Algorithms' book.. What I figured was that I implement the sorting algorithms in ruby - help me get better at ruby AND algorithms.
I've got to confess.. I'm test-infected so I'm gonna TDD my way out. This series of posts are not going to be in a walkthrough style of narration.. I'm just going to post complete samples. The order of methods indicate how the code was built up.. (the first method is the 'oldest'.

Here's merge_sort_test.rb [The Test Fixture]
--
require 'test/unit'
require 'merge_sort'
class TestMergeSort < Test::Unit::TestCase
def test_partition_array_with_even_number_of_elements
left, right = MergeSort.partition_array [11, 5, 9, 15]
assert_equal [11, 5], left
assert_equal [9, 15], right
end
def test_partition_array_with_odd_number_of_elements
left, right = MergeSort.partition_array [11, 5, 45, 9, 15]
assert_equal [11, 5], left
assert_equal [45, 9, 15], right
end

def test_merge_arrays
assert_equal( [10,20,30,40],
MergeSort.merge_arrays( [10,30], [20,40] ) )

assert_equal( [1, 3, 5, 9],
MergeSort.merge_arrays( [1, 5, 9], [3] ) )
assert_equal( [1, 3, 5, 9],
MergeSort.merge_arrays( [3], [1,5,9] ) )
end

def test_sort
assert_equal [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
MergeSort.sort([ 8, 3, 4, 0, 9, 1, 2, 7, 6, 5])
end
end


--
merge_sort.rb [The Implementation]
--
class MergeSort 
def self.partition_array( input_array)
mid_index = (input_array.length / 2) - 1
[input_array[0..mid_index], input_array[(mid_index+1)..(input_array.length-1)]]
end

def self.merge_arrays(array1, array2)
merged_array = []

until (array1.empty? || array2.empty?) do
if (array1[0] < array2[0])
merged_array << array1.shift
else
merged_array << array2.shift
end
end

merged_array + array1 + array2
end

def self.sort( input_array )
return input_array if (input_array.length < 2)

left, right = self.partition_array input_array
sortedLeft = self.sort left
sortedRight = self.sort right
y = self.merge_arrays( sortedLeft, sortedRight )
end
end



--
A command line 'runner'/'main' function
--
# Console runner / main
if !ARGV[0].nil?
input = []
ARGV.each{|x| input << x.to_i}
print MergeSort.sort(input).inspect
end


--
>ruby merge_sort.rb 90, 100, 40, 10, 45
[10, 40, 45, 90, 100]

And we're done! IMHO The Ruby Array class really shines here w.r.t. readability.

Dynamic evaluation of an expression

In this post, I'll tackle Step#2 of evaluating an expression like 2 * (3 + 5) and return 16.
  1. Convert expression from infix to postfix (see the last 2 posts)
  2. Evaluate postfix expression to determine result
As always, write a new test for ExpressionConverter


[Test]
public void TestEvaluate()
{
ExpressionConverter converter = new ExpressionConverter();
Assert.AreEqual(10, converter.EvaluateInfixExpression("((1+2) + 3) * 8/4"));
}


The implementation is very simple now that we have the ability to 'convert to postfix'.

public object EvaluateInfixExpression(string sInfixExpression)
{
List<object> postfixExpression = this.ConvertInfixToPostfix(sInfixExpression);
Stack<object> stack = new Stack<object();
foreach (object term in postfixExpression)
{
if (term is int)
{
stack.Push(term);
}
else
{
Operator operatorTerm = term as Operator;
int iValue2 = (int) stack.Pop();
int iValue1 = (int) stack.Pop();
stack.Push( operatorTerm.Evaluate(iValue1, iValue2) );
}
}
return stack.Peek();
}

Except that we don't have Operator#Evaluate()... Lets get over that hurdle. Mark this test with a temp Ignore tag. Write a new test in the TestOperator fixture

[Test]
public void TestPlusOperator_Evaluate()
{
Assert.AreEqual(30, Operator.Plus.Evaluate(10, 20));
}

If each operator could have a associated evaluate code block that evaluated 2 parameters and returned the result, we'd be done. A new member variable, a new parameterized ctor and a new code block later.. Here are the changes

public class Operator
{
public static readonly Operator Plus = new Operator("+", 1, (x, y) => x + y );
private Func<int,int,int> m_evaluateDelegate;

private Operator(string sSymbol, int iPrecedenceLevel, Func<int,int,int> evaluateDelegate):this(sSymbol, iPrecedenceLevel)
{
m_evaluateDelegate = evaluateDelegate;
}

public int Evaluate(int iValue1, int iValue2)
{
return m_evaluateDelegate(iValue1,iValue2);
}


Green. Ditto for the other operators -, *, /
All done. Finally a console app to do this


static void Main(string[] args)
{
ExpressionConverter expr = new ExpressionConverter();

Console.WriteLine("Postfix version is ");
foreach (object term in expr.ConvertInfixToPostfix(args[0]))
{ Console.Write(term + " "); }
Console.WriteLine();

Console.WriteLine("Expression evaluated to " + expr.EvaluateInfixExpression(args[0]) );
}


This is how it works.
Release>DynCalc.exe "((1+2) + 3) * 2 - 8/4"
Postfix version is
1 2 + 3 + 2 * 8 4 / -
Expression evaluated to 10


Now ExpressionConverter is no longer a converter.. we should probably rename it to Expression. Also it has no instance state. All methods can therefore be converted to static methods - no need to create an instance to invoke members. Done.
Other than non-happy paths like malformed expressions.. (can be done) it's all good. End of series. I had fun..

Test driving an infix to postfix expression converter (2 of 3)

So at the end of Post 1 of this series. we've a converter that doesn't yet understand operator precedence.
Let me refresh my memory before proceeding..
An operator token belongs to a class/family of 'Operators', has a string representation like *, +, /, - and finally has a relative precedence associated with it.
1 for +, -
2 for *, /
3 for (, )

Seems like we need an Operator class instead of just a string. I'll mark the failing test with [Ignore("Detour")] tag while we go make some operators.
Create a new test fixture, imagine a magical Operator class.. something like this


TestOperator.cs

[Test]
public void TestParse_PlusOperator()
{
Operator plusOp = Operator.Parse("+");
Assert.IsNotNull(plusOp);
Assert.AreEqual("+", plusOp.ToString());
Assert.AreEqual(1, plusOp.PrecedenceLevel);
}


I turn my ideas about Operators into a Type/Class.

public class Operator
{
private string m_OperatorSymbol;
private int m_iPrecedenceLevel;
private static readonly Operator plusOperator = new Operator("+", 1);

private Operator(string sSymbol, int iPrecedenceLevel)
{
m_OperatorSymbol = sSymbol;
m_iPrecedenceLevel = iPrecedenceLevel;
}

public int PrecedenceLevel
{
get { return m_iPrecedenceLevel; }
}
public override string ToString()
{ return m_OperatorSymbol; }


public static Operator Parse(string stringToParse)
{ return Operator.plusOperator; }
}



Green! I took the quick way out with the Parse implementation.. I'll let the coming tests force me to distill that bit of code. I add similar tests for Minus (and then Multiply and Divide). I end up with a need for a 'switch case' in Parse().
Also Parse should probably throw if its passed a token that it doesnt recognize. I'll note that down as a test too.


[Test]
[ExpectedException(ExceptionType=typeof(ArgumentException), ExpectedMessage="Unknown Operator! Cannot parse Gishu")]
public void TestParse_InvalidInput()
{
Operator noOp = Operator.Parse("Gishu");
Assert.Fail("Operator learnt some AI to parse Gishu. This should have blown up by now!");
}


[Furious typing] Alright now Operator.Parse() looks like this.. all its tests pass.

public static Operator Parse(string stringToParse)
{
switch (stringToParse)
{
case "+":
return Operator.plusOperator;
case "-":
return Operator.minusOperator;
case "*":
return Operator.multiplyOperator;
case "/":
return Operator.divisionOperator;

default:
throw new ArgumentException("Unknown Operator! Cannot parse " + stringToParse);
}
}


Now lets update our tokenizer to use this new type. This looks like it might break a few tests.. but with baby steps and a vigilant eye, it'll all be better by the time I'm done with it. I'll start by modifying one of my initial tokenizer tests...

[RowTest]
[Row("+")]
[Row(" + ")]
public void ReadPlusOperator(string sInput)
{
Tokenizer t = new Tokenizer(sInput);

//Assert.AreEqual("+", t.GetNextToken());
Assert.AreEqual(Operator.Plus, t.GetNextToken());
}


This would require us to make the static plusOperator member public. The other option is to check each member of the operator object… which would be duplication of the testfixture for Operator. So lets share our operators with the world.. make em public and rename.

public class Operator
{
public static readonly Operator Plus = new Operator("+", 1);
//...

And we're red...
TestDynCalc.TestTokenizer.ReadPlusOperator( + ):
Expected: <+>
But was: "+"


Instead of making a big bang change.. let’s make an ugly hack inside Tokenizer#GetNextToken() to make just this test pass..

Regex regexOperator = new Regex(@"^\s*([-+*/()])");
obResults = regexOperator.Match(m_sInputData);
if (obResults.Success)
{
Group obGroup = obResults.Groups[1];
RemoveReadCharacters(obGroup);

//return obGroup.Value;
if (obGroup.Value != "+")
return obGroup.Value;
else
return Operator.Plus;

}

I broke 2 tests - that tested the tokenizer with complete expressions containining +. Turns out its easy to fix them.

[Test]
public void ReadMultipleTokens()
{
Tokenizer t = new Tokenizer(" 2 + 3 - 34 * 2 / 1 ");
//object[] arrExpectedTokens = new object[] { 2, "+", 3, "-", 34, "*", 2, "/", 1 };
object[] arrExpectedTokens = new object[] { 2, Operator.Plus, 3, "-", 34, "*", 2, "/", 1 };
foreach (object token in arrExpectedTokens)
{
Assert.AreEqual(token, t.GetNextToken());
}
}

All green. Excuse me while I repeat the procedure for all the other operators. The hack in Tokenizer#GetNextToken() can now be replaced by ...

return Operator.Parse(obGroup.Value);


However we forgot the parantheses bros. while creating our operators. We need more operators! Mark Tokenizer with Ignore(“2 TDDed operators coming right up…”).. [more furious typing] we have new operators. Take off the ignore tag. Similar changes… and Tokenizer is now Operator-aware.
Time to take off the ignore tag on ExpressionConverter tests and end our little detour.
So we're back to red.. but this time, we've operators with precedence. [after some mental acrobatics with a pencil and an eraser on paper]
The key to getting this is to check if the operator on top of stack is not a '(' and has higher precedence than the incoming/current token. If yes, pop the stack, write popped operator to output and retry. If no, push the incoming token onto the stack.
So + should not be pushed if the top of stack[TOS] contains *; however * should be if TOS is +.
So we add some more code to the final else block in ExpressionConverter#ConvertToPostfix..


if (obStack.Count() > 0)
{
Operator termOnTopOfStack = obStack.Peek() as Operator;
if ((termOnTopOfStack != Operator.OpenParantheses)
&& (termOnTopOfStack.PrecedenceLevel > (term as Operator).PrecedenceLevel))
{
postfixExpr.Add(obStack.Pop());
continue;
}
}

obStack.Push(term);


All Green! Woohoo! However the method seems to have grown to an uncomfortable size for me... maybe I can refactor.

  • Rename method to ExpressionConverter#ConvertInfixToPostfix()

  • Stack always contains Operators.. So we can do away the casting...Stack stackOfOperators

  • Replace ‘term.ToString() == ")" ‘ with type-based checks

  • Each of ( and ) is a parenthesis together they make a set of parentheses. http://en.wikipedia.org/wiki/Parenthesis... well you live, you read wikis, you learn. Correct typos

  • Extract some methods to clarify intent.
    Had to promote the stack and postfixExpr variables to class members. (All the extracted methods required the stack and List variables to be passed in)



Looking good. I'll post the refactored version shortly. Let's try another expression/test.


[Row("0-12000-(16*4)-20", "0 12000 - 16 4 * - 20 -")]


Red again! [A few brain cycles later]
This breaks because the converter doesn’t recognize Left to Right precedence for operators at the same level. (In 0 - 5 + 3, - should be performed first to get the result of -2 even though precedence-wise + and - are equivalent.)
But this can be easily solved by replacing > with >= where we compare operator precedence. Here’s the final version of the class.


public class ExpressionConverter
{
List<object> m_postfixExpr = new List<object>();
Stack<Operator> m_stackOfOperators = new Stack<Operator>();
public List<Object> ConvertInfixToPostfix(string sInfixExpr)
{
m_postfixExpr.Clear(); m_stackOfOperators.Clear();

Tokenizer parser = new Tokenizer(sInfixExpr);
object term = parser.GetNextToken();
while (term != null)
{
if (term is int)
{
m_postfixExpr.Add(term);
}
else if (term == Operator.CloseParenthesis)
{
MoveOperatorsOnStackToPostfixExprTillMatchingOpenParenthesisIsFound();
}
else
{
Operator operatorTerm = term as Operator;
if (OperatorOnTopOfStackHasHigherOrSamePrecedenceAs(operatorTerm))
{
m_postfixExpr.Add(m_stackOfOperators.Pop());
continue;
}

m_stackOfOperators.Push(operatorTerm);
}

term = parser.GetNextToken();
}

PopAllRemainingOperatorsOnStackToPostfixExpr();
return m_postfixExpr;
}

private bool OperatorOnTopOfStackHasHigherOrSamePrecedenceAs(Operator term)
{
if (m_stackOfOperators.Count() == 0)
return false;

Operator termOnTopOfStack = m_stackOfOperators.Peek();
return ((termOnTopOfStack != Operator.OpenParenthesis)
&& (termOnTopOfStack.PrecedenceLevel >= term.PrecedenceLevel));
}

private void MoveOperatorsOnStackToPostfixExprTillMatchingOpenParenthesisIsFound()
{
Operator term = m_stackOfOperators.Pop();
while (term != Operator.OpenParenthesis)
{
m_postfixExpr.Add(term);
term = m_stackOfOperators.Pop();
}
}

private void PopAllRemainingOperatorsOnStackToPostfixExpr()
{
while (m_stackOfOperators.Count > 0)
m_postfixExpr.Add(m_stackOfOperators.Pop());
}
}


Code is good. End of post. In the next post, I'll write a console 'main' app to exercise the converter and evaluate the expression.

Test driving an infix to postfix expression converter (1 of 2)

I've been wanting to understand infix to postfix conversion - strangely intriguing to me. Here's what I'm about to ramble on for a while today...
Given an expression in infix form (operators appear inline in the expression) like
3 * (2 + 5)
Transform it to its postfix equivalent
3 2 5 + *


This form can be easily evaluated by a computer. You keep pushing terms onto a stack.. everytime you hit a operator, you pop the last 2 values and perform the operation, push the result back on the stack. In time, you will run out of terms and have the result at the top of the stack.
e.g. Stack builds from left to right (TOS is extreme right)
Read 3 Stack [3]
Read 2 Stack [3 2]
Read 5 Stack [3 2 5]
Read + Stack [3 7] #Pop 5,2 Perform 2+5, Store 7 back on stack
Read * Stack [21] # Pop 7,3 Perform 3*7, Store 21 back on stack.


Time and again I've procrastinated.. Then I hit Bart De Smet's blog post dated Oct 2006 - It's time! :). You may want to read up on the algorithm to parse an infix expression.

Just to make things interesting I'm going to do it TDD style.. red-green-refactor to glory. I'm trying to shorten the post to the essence.

I've TDDed myself a Tokenizer, a class that parses a string, uses a couple of regular expressions and returns the next number/operator with each call to GetNextToken().

Tokenizer.cs


public class Tokenizer
{
string m_sInputData;
public Tokenizer(string sInput)
{ m_sInputData = sInput; }

public object GetNextToken()
{
Regex regexNumber = new Regex(@"^\s*(\d+)");
Match obResults = regexNumber.Match(m_sInputData);
if (obResults.Success)
{
Group obGroup = obResults.Groups[1];
RemoveReadCharacters(obGroup);
return Int32.Parse(obGroup.Value);
}

Regex regexOperator = new Regex(@"^\s*([-+*/()])");
obResults = regexOperator.Match(m_sInputData);
if (obResults.Success)
{
Group obGroup = obResults.Groups[1];
RemoveReadCharacters(obGroup);
returnobGroup.Value;
}

return null;
}

private void RemoveReadCharacters(Group obMatchedGroup)
{
m_sInputData = m_sInputData.Remove(0, obMatchedGroup.Index + obMatchedGroup.Length);
}
}


The tokenizer has around 20 tests. I'll post one of the latter tests to illustrate usage

TestTokenizer.cs

[Test]
public void ReadMultipleTokensWithParantheses()
{
Tokenizer t = new Tokenizer(" ( 1 + 2 ) * (3 - (8/2))");
object[] arrExpectedTokens = new object[] { "(", 1, "+", 2, ")", "*", "(", 3, "-", "(", 8, "/", 2, ")", ")" };
foreach (object token in arrExpectedTokens)
{
Assert.AreEqual(token, t.GetNextToken());
}
}


All set to start with the meat of the problem: ExpressionConverter. So we'll come up with out first test employing some wishful thinking. The output is going to be reordered sequence of numbers and operators.. hence List<objects>

TestExpressionConverter.cs

[Test]
public void TestConvert_Simple()
{
ExpressionConverter converter = new ExpressionConverter();
List<object> postfixExpr = converter.ConvertToPostfix(" 2 + 3 ");
StringBuilder sb = new StringBuilder();
foreach(object term in postfixExpr)
{
sb.AppendFormat("{0} ", term.ToString());
}
Assert.AreEqual("2 3 +", sb.ToString());
}


To make this compile, I need to define the ExpressionConverter class and the ConvertToPostfix method within it. Something like this

public List<Object> ConvertToPostfix(string sInfixExpr)
{
List<object> postfixExpr = new List<object>();
Stack<object> obStack = new Stack<object>();

Tokenizer parser = new Tokenizer(sInfixExpr);
object term = parser.GetNextToken();
while (term != null)
{
if (term is int)
{ postfixExpr.Add(term); }
else
{ obStack.Push(term); }

term = parser.GetNextToken();
}

while (obStack.Count > 0)
postfixExpr.Add(obStack.Pop());

return postfixExpr;
}


The simplest thing that works. Collect all numeric terms in the result List<>, push operators onto the stack. At the end, pop contents of the stack into the List. Green!
Let's turn on the heat, see how it deals with grouping. Since the test is basically the same, albeit with diff input and hence output, I found an unorthodox way to use the RowTest NUnit extension I blogged about earlier. I make a couple of changes to the test like this... The last parameter in the list is the ExpectedValue for the test. So now I can run the same test with different input and expected values by adding Row Attributes. Might be a bit hard to read for the new guy.. but not too bad.



[RowTest]
[Row(" 2 + 3 ", "2 3 +")]
[Row(" 2 + (30 + 50 ) ", "2 30 50 + +")]
public void TestConvertInfixToPostfix(string sInfixExpr, string sExpectedPostfixExpr)
{
ExpressionConverter converter = new ExpressionConverter();
List<object> postfixExpr = converter.ConvertInfixToPostfix(sInfixExpr);

StringBuilder sb = new StringBuilder();
foreach(object term in postfixExpr)
{
sb.AppendFormat("{0} ", term.ToString());
}
Assert.AreEqual(sExpectedPostfixExpr, sb.ToString().Trim());
}


This fails as expected. Our code doesn't do parentheses yet. When we read a ), we need to pop out all operators till the matching (. Both ( ) are discarded and never part of the postfix expression. We can make this change in ConvertToPostfix()

if (term is int)
{
postfixExpr.Add(term);
}

else if (term.ToString() == ")")
{
object poppedTerm = obStack.Pop();
while (poppedTerm.ToString() != "(")
{
postfixExpr.Add(poppedTerm);
poppedTerm = obStack.Pop();
}
}

else
{
obStack.Push(term);
}


and back to Green. Lets take it up a notch. Add a new Row attribute / new test with the following expression

[Row(" ( (10+20) + 30 ) * 20-8/4 ", "10 20 + 30 + 20 * 8 4 / -")]


The test fails. NUnit reports:
TestDynCalc.TestExpressionConverter.TestConvertToPostfix( ( (10+20) + 30 ) * 20-8/4 , 10 20 + 30 + 20 * 8 4 / -):
String lengths are both 25. Strings differ at index 16.
Expected: "10 20 + 30 + 20 * 8 4 / -"
But was: "10 20 + 30 + 20 8 4 / - *"
---------------------------^


Bitten by operator precedence.. * has precedence over -. Is this the end for our converter? Not quite.. Onto Part 2


My solution for UncleBob's Mark IV CoffeeMaker - 4

Back to Part3?
Part 4: Fresh Coffee at the end of this post!
Story#2. The Warmer Plate is turned on only when the pot is present on it.
Going back to my lil seq diagrams, we see that this one is similar to the previous one. We let the WarmerPlateStatus changed event tell us when the pot has been moved off the plate and toggle the heater on/off accordingly.

[Test]
public void Test_WarmerHeaterIsTurnedOff_WhenPotWithCoffeeIsTakenOffThePlate()
{
m_obDevice.WarmerPlateStatus = WarmerPlateStatus.POT_NOT_EMPTY;
Assert.AreEqual(WarmerState.ON, m_obDevice.WarmerPlateState,
"Warmer Plate should be ON if there's a pot with cofee on it");

m_obDevice.WarmerPlateStatus = WarmerPlateStatus.WARMER_EMPTY;
Assert.AreEqual(WarmerState.OFF, m_obDevice.WarmerPlateState,
"Warmer Plate should be turned off");
}

And to make that go Green

void On_WarmerPlateStatusChanged(object sender, EventArgs obEvtArgs)
{
...
if (WarmerPlateStatus.POT_NOT_EMPTY == m_obDevice.GetWarmerPlateStatus())
{
m_obDevice.SetWarmerState(WarmerState.ON);
}
else
{
m_obDevice.SetWarmerState(WarmerState.OFF);
}
}

Easy enough.. complete the rest.

  • Test_WarmerPlateStaysOff_WhenEmptyPotIsReplacedOnPlate
  • Test_WarmerPlateIsTurnedOn_WhenEmptyPotStartsCollectingCoffee
  • Test_WarmerPlateStaysOff_WhenEmptyPotIsTakenFromThePlate
  • Test_WarmerPlateIsTurnedOn_WhenPotWithCoffeeIsReplacedOnPlate
Story#3: When the Brew Button is pressed, the CoffeeMaker makes Coffee.
The description is in the book. The user places the filter with coffee grounds, pours water and presses the BrewButton. The indicator light goes off till Coffee is ready. This just seems like too big a bite..
The CoffeeMaker’s BrewButton is an auto-resetting button. So we add that into FakeCoffeeMaker.

public BrewButtonStatus GetBrewButtonStatus()
{
BrewButtonStatus eBrewButtonStatus = m_eBrewButtonStatus;
m_eBrewButtonStatus = BrewButtonStatus.NOT_PUSHED;
return eBrewButtonStatus;
}

The test for this isn’t flowing to me. I’ll look at the rough seq diagram I drew up.. Ah! the huge seq diagram is scaring me.. I need to break this diagram into multiple tests

  1. Test_BrewButtonPressed
  2. Test_BrewButtonPressed_ButTheUserForgotToPourWater
  3. Test_IndicatorLightIsTurnedON_AsSoonAsCoffeeIsReady
  4. Test_BoilerIsTurnedOFF_WhenWaterIsExhausted

[Test]
public void Test_BrewButtonPressed()
{
Assert.AreEqual(BoilerState.OFF, m_obFakeDevice.BoilerState);
Assert.AreEqual(IndicatorState.ON, m_obFakeDevice.IndicatorState);

m_obFakeDevice.SimulateUser_PlaceFilter_PourWater_And_PressTheBrewButton();

Assert.AreEqual(BoilerState.ON, m_obFakeDevice.BoilerState,
"Boiler must be turned on to heat the water");
Assert.AreEqual(IndicatorState.OFF, m_obFakeDevice.IndicatorState,
"Indicator light must go off to indicate CoffeeMaker is busy");
}

So to make this compile I need to update FakeCoffeeMaker with (I know its an awfully big method name..)

internal void SimulateUser_PlaceFilter_PourWater_And_PressTheBrewButton()
{
m_eBoilerStatus = BoilerStatus.NOT_EMTPY;
PressBrewButton();
}

Alright we have a red to go ahead.. So first the CoffeeMaker has to know when the BrewButton is pressed. The Observer can help us with that.

public void Monitor(CoffeeMakerAPI obDevice)
{
...
m_obObserver.WarmerPlateStatusChanged += new EventHandler(On_WarmerPlateStatusChanged);
m_obObserver.BrewButtonPressed += new EventHandler(On_BrewButtonPressed);

On_WarmerPlateStatusChanged(this, EventArgs.Empty);
}

void On_BrewButtonPressed(object sender, EventArgs e)
{
m_obDevice.SetBoilerState(BoilerState.ON);
m_obDevice.SetIndicatorState(IndicatorState.OFF);
}

Green. Next we handle the error scenarios. The user can forget the filter (and I presume he may get hot water.. not too bad.. I’ll skip that one). But if he forgets to add water, we don’t want our boiler all heated up for nothing. So

[Test]
public void Test_BrewButtonPressed_ButTheUserForgotToPourWater()
{
Assert.AreEqual(BoilerState.OFF, m_obFakeDevice.BoilerState);
Assert.AreEqual(IndicatorState.ON, m_obFakeDevice.IndicatorState);

m_obFakeDevice.SimulateUser_PlaceFilter_And_PressTheBrewButton();

Assert.AreEqual(BoilerState.OFF, m_obFakeDevice.BoilerState,
"Boiler must stays off since there is no water in the boiler");
Assert.AreEqual(IndicatorState.ON, m_obFakeDevice.IndicatorState,
"Indicator light stays as is as CoffeeMaker refuses to work without water");
}

Now I can add another method to this thing, which leaves out the ‘Pour Water’ part. But something doesn’t feel right. I might as well as kill off the Lazy Method & have separate methods for each user action. Like this.

m_obFakeDevice.SimulateUser_PlaceFilterWithCoffeeGrounds();
m_obFakeDevice.SimulateUser_PressTheBrewButton();

I get squiggly lines and I use my newfound IDE ninja knowledge ‘Ctrl + . + Enter’ to generate the stub methods. Then Ctrl+Alt+DownArrow + F(akeCoffeeMaker) + Enter to switch over to the class.

internal void SimulateUser_PlaceFilterWithCoffeeGrounds()
{
return;
}

internal void SimulateUser_PressTheBrewButton()
{
return;
}

Now I see we already have a PressBrewButton… that we can rename. Delete the new stub#2. Stub#1 can stay as is.. just to add to readability of the test. Build and good.. red test.
Simple fix.. add a guard clause and we’re green.

void On_BrewButtonPressed(object sender, EventArgs e)
{
if (m_obDevice.GetBoilerStatus() == BoilerStatus.EMPTY)
{
return;
}
...

We’ll update the previous test to be consistent and readable as follows. So the previous test now reads...

[Test]
public void Test_BrewButtonPressed()
{
...
m_obFakeDevice.SimulateUser_PlaceFilterWithCoffeeGrounds();
m_obFakeDevice.SimulateUser_PoursWater();
m_obFakeDevice.SimulateUser_PressTheBrewButton();
...
}


Next up is

[Test]
public void Test_IndicatorLightIsTurnedON_AsSoonAsCoffeeIsReady()
{
Test_BrewButtonPressed();

m_obFakeDevice.WarmerPlateStatus = WarmerPlateStatus.POT_NOT_EMPTY;

Assert.AreEqual(IndicatorState.ON, m_obFakeDevice.IndicatorState,
"Indicator light comes back on - 'Coffee Ready'");
}

And red straight away.. Make the following changes to Coffee_Maker.Brew

void On_BrewButtonPressed(object sender, EventArgs e)
{
...

m_obDevice.SetBoilerState(BoilerState.ON);
m_obDevice.SetIndicatorState(IndicatorState.OFF);

m_obObserver.WarmerPlateStatusChanged += new EventHandler(On_WarmerPlateStatusChangedAfterBrew);
}

void On_WarmerPlateStatusChangedAfterBrew(object sender, EventArgs e)
{
if (m_obDevice.GetWarmerPlateStatus() != WarmerPlateStatus.POT_NOT_EMPTY)
{ return; }
m_obDevice.SetIndicatorState(IndicatorState.ON);
m_obObserver.WarmerPlateStatusChanged -= new EventHandler(On_WarmerPlateStatusChangedAfterBrew);

}

Neat. Now on to the final one.

[Test]
public void Test_BoilerIsTurnedOFF_WhenWaterIsExhausted()
{
Test_BrewButtonPressed();

m_obFakeDevice.SetBoilerStatus(BoilerStatus.EMPTY);

Assert.AreEqual(BoilerState.OFF, m_obFakeDevice.BoilerState,
"Boiler should have been turned off since there is no more water to heat");
}

Red.. Back to Coffee_Maker

void On_BrewButtonPressed(object sender, EventArgs e)
{
...

m_obDevice.SetBoilerState(BoilerState.ON);
m_obObserver.BoilerEmpty += new EventHandler(On_BoilerEmpty);
m_obDevice.SetIndicatorState(IndicatorState.OFF);
m_obObserver.WarmerPlateStatusChanged += new EventHandler(On_WarmerPlateStatusChangedAfterBrew);
}

void On_BoilerEmpty(object sender, EventArgs e)
{
m_obDevice.SetBoilerState(BoilerState.OFF);
m_obObserver.BoilerEmpty -= new EventHandler(On_BoilerEmpty);
}

All Green. Now I update my visual CoffeeMakerView that I built to strap on a Coffee_Maker to monitor the FakeCoffeeMakerDevice and see the magic happen. I need to make some of the internal test helper FakeCoffeeMaker methods public. Warm Fuzzy Glow! It is alive!!! [CoffeeMakerTestApp\bin\Release\CoffeeMakerTestApp.exe]



Thought of one more test.. Ready Indicator doesn't stays OFF if the pot already had some old coffee in it. Add a new test and make it green by only turning off the light and subscribing for notifications if we have an empty pot on the plate. Done!
Turn the page..

My solution for UncleBob's Mark IV CoffeeMaker - 3

Back to Part 2?
Part 3: Beware of threads

The CoffeeMaker opens the Relief valve in case someone takes the coffee pot off the plate to prevent coffee from falling onto the plate
From the seq dia #2,the CoffeeMaker just needs to listen for changed events from the WarmerPlate.
If new status is WarmerEmpty, open the valve to reduce pressure/stop water flow. Else keep it closed.

[TestFixture]
public class TestCoffee_Maker
{
private const int I_WAIT_FOR_EVENTS_TO_FIRE = 300;
[Test]
public void Test_ValveIsOpened_IfCoffeePotIsRemoved_ElseClosed()
{
Coffee_Maker obCoffeeMaker = new Coffee_Maker();
FakeCoffeeMakerDevice obDevice = new FakeCoffeeMakerDevice();
obCoffeeMaker.Monitor(obDevice);
obDevice.WarmerPlateStatus = WarmerPlateStatus.POT_NOT_EMPTY;
Thread.Sleep(I_WAIT_FOR_EVENTS_TO_FIRE);

Assert.AreEqual(ReliefValveState.CLOSED, obDevice.ReliefValveState,
"Relief valve should be closed when Pot With Coffee is on the plate");
obDevice.WarmerPlateStatus = WarmerPlateStatus.WARMER_EMPTY;
Thread.Sleep(I_WAIT_FOR_EVENTS_TO_FIRE);

Assert.AreEqual(ReliefValveState.OPEN, obDevice.ReliefValveState,
"Relief valve should be open since the warmer plate is now empty");

}
}

Red! make it pass like this.

public class Coffee_Maker
{
SensorObserver m_obObserver;
CoffeeMakerAPI m_obDevice;

public void Monitor(CoffeeMakerAPI obDevice)
{
m_obObserver = new SensorObserver();
m_obDevice = obDevice;

m_obObserver.Observe(m_obDevice);
m_obObserver.WarmerPlateStatusChanged += new EventHandler(On_WarmerPlateStatusChanged);

}

void On_WarmerPlateStatusChanged(object sender, EventArgs obEvtArgs)
{
if (WarmerPlateStatus.WARMER_EMPTY == m_obDevice.GetWarmerPlateStatus())
{
m_obDevice.SetReliefValveState(ReliefValveState.OPEN);
}
}
}

Next we extend to check if it is closed when the pot is placed back on it. On second thoughts.. let me write 4 test cases for each transition… be thorough. One at at time.. Improve the name of the first one

public void Test_ValveIsOpened_IfPotWithCoffeeIsRemovedFromThePlate() {..}
[Test]
public void Test_ValveIsClosed_IfPotWithCoffeeIsReplaced ()
{
Coffee_Maker obCoffeeMaker = new Coffee_Maker();
FakeCoffeeMakerDevice obDevice = new FakeCoffeeMakerDevice();
obCoffeeMaker.Monitor(obDevice);
obDevice.WarmerPlateStatus = WarmerPlateStatus.WARMER_EMPTY;
Thread.Sleep(I_WAIT_FOR_EVENTS_TO_FIRE);

Assert.AreEqual(ReliefValveState.OPEN, obDevice.ReliefValveState,
"Relief valve should be open since the warmer plate is now empty");
obDevice.WarmerPlateStatus = WarmerPlateStatus.POT_NOT_EMPTY;
Thread.Sleep(I_WAIT_FOR_EVENTS_TO_FIRE);

Assert.AreEqual(ReliefValveState.CLOSED, obDevice.ReliefValveState,
"Relief valve should be closed when Pot With Coffee is on the plate");
}

Make it green by

void On_WarmerPlateStatusChanged(object sender, EventArgs obEvtArgs)
{
if (WarmerPlateStatus.WARMER_EMPTY == m_obDevice.GetWarmerPlateStatus())
{
m_obDevice.SetReliefValveState(ReliefValveState.OPEN);
}
else
{
m_obDevice.SetReliefValveState(ReliefValveState.CLOSED);
}
}

Still red ??!! aha.. hit upon a special case. If the coffee maker is started with no pot on the plate, the valve should be open. Since no ‘change’ occurs.. event is never fired. We can fix that by calling the above function at the end of Monitor() to initialize the valve correctly.. Done
Refactoring time: Move common code to a Setup method and extract local variables to members
The second test fails intermittently… bad omen. Is it because two threads are accessing the same variable.? think the variable needs to be marked as volatile. Still no luck.

Looks like my TDD badge is going to be revoked. I put in some consoles traces to see if the event is being raised.

A detour into 'Thrashing around in a multi-threaded environment'
I find that when the test fails, the LastPlateStatus is WARMER_EMPTY to begin with.. hence the event is never raised. The consoles/traces are:
Start Listener thread
Change to WE
Listener thread active
Check WARMER_EMPTY with WARMER_EMPTY
Check WARMER_EMPTY with WARMER_EMPTY
Check WARMER_EMPTY with WARMER_EMPTY
Check WARMER_EMPTY with WARMER_EMPTY


And when it works
Start Listener thread
Listener thread active
Check POT_EMPTY with POT_EMPTY
Change to WE
Check WARMER_EMPTY with POT_EMPTY
WARMER_EMPTY <= POT_EMPTY Check WARMER_EMPTY with WARMER_EMPTY Check WARMER_EMPTY with WARMER_EMPTY Check POT_NOT_EMPTY with WARMER_EMPTY POT_NOT_EMPTY <= WARMER_EMPTY Check POT_NOT_EMPTY with POT_NOT_EMPTY Check POT_NOT_EMPTY with POT_NOT_EMPTY


Batman to the drawing board. I trace out the seq of events. (Unnecessary in hind sight..I can see that the issue is clear from the above traces).
Aha! In the RED Case, The listener thread starts after the WarmerPlateStatus has been changed to WE.. i.e. the listener thread is slow off the blocks.
From my doodling, I see that it’d be better if I ensure that the listener thread is started before the SensorObserver.Observe method exits. Let’s see if that is the problem.

public void Observe(CoffeeMakerAPI obDevice)
{
m_obDevice = obDevice;
obListenerThread = new Thread(new ThreadStart(ListenForChanges));
obListenerThread.Start();

WaitTillListenerThreadHasStarted();
Console.WriteLine("Start Listener thread ");
}
private void WaitTillListenerThreadHasStarted()
{
while (obListenerThread.ThreadState != ThreadState.Running) ;
}

private void ListenForChanges()
{
Console.WriteLine("Listener thread active");
...


Aaarghh!! Still intermittent red. When in doubt.. I add more traces.. (expert TDDer at work here.. NOT)

public void Observe(CoffeeMakerAPI obDevice)
{
m_obDevice = obDevice;
obListenerThread = new Thread(new ThreadStart(ListenForChanges));
obListenerThread.Start();

Console.WriteLine("Start Listener thread ");
WaitTillListenerThreadIsRunning();
Console.WriteLine("Out of Observe!");
}

private void ListenForChanges()
{
Console.WriteLine("Listener thread active");
BoilerStatus eLastBoilerStatus = m_obDevice.GetBoilerStatus();
WarmerPlateStatus eLastPlateStatus = m_obDevice.GetWarmerPlateStatus();
Console.WriteLine("First Status Read");
while ( !m_bStopWatching )
{


Now when it fails.. the log is
Start Listener thread
Out of Observe!
Listener thread active
Change to WE
First Status Read
Check WARMER_EMPTY with WARMER_EMPTY
Check WARMER_EMPTY with WARMER_EMPTY
Check WARMER_EMPTY with WARMER_EMPTY
Check WARMER_EMPTY with WARMER_EMPTY


Aha! The thread has started but just before it could initialize the LastXXX status variables, there is a thread switch and the value is changed to WE. If we promote the LastXXX variables to volatile local variables and ensure that they are always initialized before the listener thread is started.. hmm. lets see if this works…
Hallelujah! Console.WriteLines rock()



private volatile BoilerStatus m_eLastBoilerStatus;
private volatile WarmerPlateStatus m_eLastPlateStatus;

public void Observe(CoffeeMakerAPI obDevice)
{
m_obDevice = obDevice;
m_eLastBoilerStatus = m_obDevice.GetBoilerStatus();
m_eLastPlateStatus = m_obDevice.GetWarmerPlateStatus();
Console.WriteLine("First Status Read");
obListenerThread = new Thread(new ThreadStart(ListenForChanges));
obListenerThread.Start();

Console.WriteLine("Start Listener thread ");
Console.WriteLine("Out of Observe!");
}

private void ListenForChanges()
{
Console.WriteLine("Listener thread active");
while ( !m_bStopWatching )
{



Now the logs show.
First Status Read
Start Listener thread
Out of Observe!
Listener thread active
Check POT_EMPTY with POT_EMPTY
Change to WE
Check WARMER_EMPTY with POT_EMPTY
WARMER_EMPTY <= POT_EMPTY


Turn the crank another 20 times.. All green and good. I’ll remove all the logging lines.. Goodbye friends!
More duplication I see that we have repeating occurrences of
m_obDevice.Property = value
Thread.Sleep(I_WAIT_FOR_EVENTS_TO_FIRE);
How about we move the delay into the FakeCoffeeMaker property.. then we don’t need to define the constant in each test fixture.

public class FakeCoffeeMakerDevice : CoffeeMakerAPI
{
private const int I_WAIT_FOR_EVENTS_TO_FIRE = 300;

public WarmerPlateStatus WarmerPlateStatus
{
get { return m_eWarmerPlateStatus; }
set
{
m_eWarmerPlateStatus = value;
Thread.Sleep(I_WAIT_FOR_EVENTS_TO_FIRE);
}
}

Look how pretty my tests are now.. Act-Arrange-Assert appears again to knight ‘em as SirGoodTest.

[Test]
public void Test_ValveIsOpen_IfPotWithCoffeeIsRemovedFromThePlate()
{
m_obDevice.WarmerPlateStatus = WarmerPlateStatus.POT_NOT_EMPTY;
Assert.AreEqual(ReliefValveState.CLOSED, m_obDevice.ReliefValveState,
"Relief valve should be closed when Pot With Coffee is on the plate");

m_obDevice.WarmerPlateStatus = WarmerPlateStatus.WARMER_EMPTY;

Assert.AreEqual(ReliefValveState.OPEN, m_obDevice.ReliefValveState,
"Relief valve should be open since the warmer plate is now empty");
}

Watch in awe ... haphazard refactoring ninja on steroids
Repeat the procedure for TestSensorObserver fixture.. add delays to PressBrewButton() and SetBoilerStatus(). Cool Green!
Exposed! The Missing Dispose! Hey we’re missing SensorObserver.Dispose() in the third test. I should have mistake-proofed that by adding a Teardown method that does that.. never too late.

Which brings me to… I’m not doing SensorObserver.Dispose() in our TestCoffeeMaker tests. Lets add a Dispose to CoffeeMaker that delegates the call and call it from Teardown. Green!
I’ll just add two tests to complete the set.
  • Test_ValveIsOpened_IfPotWithCoffeeIsTakenOffThePlate
  • Test_ValveIsClosed_IfPotWithCoffeeIsReplaced
  • Test_ValveIsOpened_IfEmptyPotIsTakenOffThePlate
  • Test_ValveIsClosed_IfEmptyPotIsReplacedOnPlate

what about the transition PE => PNE (The pot starts collecting coffee). Lets add that one too
  • Test_ValveIsClosed_IfEmptyPotIsReplacedOnPlate
Turn the page...

My solution for UncleBob's Mark IV CoffeeMaker - 2

Part 2: Watch those sensors
From my little design exercise, it looks like we need someone who will poll the sensors periodically and alert us with events.
I have already created an implementation of the CoffeeMakerAPI interface called FakeCoffeeMakerDevice that we'll use for our task.
Test first.. here we go

[TestFixture]
public class TestSensorObserver
{

private int m_iNotificationCount;
[SetUp]
public void Setup()
{
m_bEventRaised = 0;
}

[Test]
public void Test_BrewButtonPressedEvent_IsRaised()
{
SensorObserver obObserver = new SensorObserver();
FakeCoffeeMakerDevice obCoffeeMaker = new FakeCoffeeMakerDevice();
obObserver.Observe(obCoffeeMaker);
obObserver.BrewButtonPressed += new EventHandler(On_Event_Raised);

obCoffeeMaker.PressBrewButton();
Thread.Sleep(300);

obObserver.Dispose();
Assert.IsTrue(m_bEventRaised, "BrewButton Pressed But SensorObserver didnt notify
us"
);
}

private void On_Event_Raised(object sender, EventArgs e)
{
m_bEventRaised = true;
}


Now the code to make this pass turned out to be a bit longwinded. TDD with multithreading right off the bat.


public class SensorObserver
{
private CoffeeMakerAPI m_obDevice;

public event EventHandler BrewButtonPressed;

private bool m_bStopWatching = false;
private Thread obListenerThread;

private bool m_bIsDisposed = false;

public void Observe(CoffeeMakerAPI obDevice)
{
m_obDevice = obDevice;
obListenerThread = new Thread(new ThreadStart(ListenForChanges));
obListenerThread.Start();
}

private void ListenForChanges()
{
while ( !m_bStopWatching )
{
if (BrewButtonStatus.PUSHED == m_obDevice.GetBrewButtonStatus())
{
if (null != this.BrewButtonPressed)
{
this.BrewButtonPressed(this, EventArgs.Empty);
}
}

Thread.Sleep(100);
}
}

public void Dispose()
{
if (m_bIsDisposed)
{ return; }
m_bStopWatching = true;
obListenerThread.Join(2000);
m_bIsDisposed = true;
}
}


  • Add a similar test for BoilerEmpty event. Done.
  • Refactor common test code into setup and teardown.
  • Remove the magic numbers related to delays for threads


[TestFixture]
public class TestSensorObserver
{
SensorObserver obObserver;
FakeCoffeeMakerDevice obCoffeeMaker;
private int m_iNotificationCount;

const int I_WAIT_FOR_EVENTS_TO_FIRE = 300;

[SetUp]
public void Setup()
{
m_iNotificationCount = 0;

obObserver = new SensorObserver();
obCoffeeMaker = new FakeCoffeeMakerDevice();
obObserver.Observe(obCoffeeMaker);
}

[Test]
public void Test_BrewButtonPressedEvent_IsRaised()
{
obObserver.BrewButtonPressed += new EventHandler(On_Event_Raised);

obCoffeeMaker.PressBrewButton();
Thread.Sleep(I_WAIT_FOR_EVENTS_TO_FIRE);

obObserver.Dispose();
Assert.IsTrue(m_iNotificationCount != 0, "BrewButton Pressed But SensorObserver didnt notify us");
}
...

But now it seems that the Sensor Observer would nag us with events till we put some water in the boiler. We want only one notification when the boiler goes from NOT_EMPTY to EMPTY. (Not a problem with Brew Button since the spec says that the CoffeeMaker auto-resets it to NOT_PUSHED.)
Looks like we need a test to verify that only one event is raised. We could write a new test but that would be the same as the previous one except for the end assertion. How about if we use an integer value instead of a boolean to check for event notifications.. we could then check m_iNotification == 1 to verify that the event was raised.. and only once.
Turns out I need to add another delay before setting BoilerState to EMPTY in the test else the change is too fast for SensorObserver to see.

[Test]
public void Test_BoilerEmptyEvent_IsRaised_ExactlyOnce()
{
obCoffeeMaker.SetBoilerStatus(BoilerStatus.NOT_EMTPY);
Thread.Sleep(I_WAIT_FOR_EVENTS_TO_FIRE);
obObserver.BoilerEmpty += new EventHandler(On_Event_Raised);

obCoffeeMaker.SetBoilerStatus(BoilerStatus.EMPTY);
Thread.Sleep(I_WAIT_FOR_EVENTS_TO_FIRE);

obObserver.Dispose();
Assert.IsTrue(m_iNotificationCount == 1, "Boiler has run out of water but SensorObserver has notified us {0} times", m_iNotificationCount);
}

Code to make that green:

private void ListenForChanges()
{
BoilerStatus eLastBoilerStatus = m_obDevice.GetBoilerStatus();
while ( !m_bStopWatching )
{
...

BoilerStatus eCurrentBoilerStatus = m_obDevice.GetBoilerStatus();
if ((BoilerStatus.EMPTY == eCurrentBoilerStatus) && (eCurrentBoilerStatus != eLastBoilerStatus))
{
if (null != this.BoilerEmpty)
{
this.BoilerEmpty(this, EventArgs.Empty);
}
}
eLastBoilerStatus = eCurrentBoilerStatus;
Thread.Sleep(FOR_100_MILLISEC);
}

Great. Next we need a notification which lets us know of changes in the WarmerPlateStatus… and I‘m beginning to feel like a BDUFish (building up a component without a user story).. but this is the last event .. I’ll trudge on.
The WP can be in 3 states.. let me draw up a quick state diagram.
Shows that there are 5 valid transitions.. (Invalid Transitions: PotNotEmpty ->PotEmpty. PotEmpty->WarmerEmpty is suspect but I’ll let it slide.. (Wally just checked if there’s any… and snuck it back.. The puppet master shall lie in wait).
Hmm as I think about it.. I just need a changed notification.. the new value can be queried.. Let see if we can do with a simple ‘changed’ event..

[Test]
public void Test_WarmerPlateStatusChanged()
{
obCoffeeMaker.WarmerPlateStatus = WarmerPlateStatus.POT_EMPTY;
Thread.Sleep(I_WAIT_FOR_EVENTS_TO_FIRE);
obObserver.WarmerPlateStatusChanged += new EventHandler(On_Event_Raised);

obCoffeeMaker.WarmerPlateStatus = WarmerPlateStatus.POT_NOT_EMPTY;
Thread.Sleep(I_WAIT_FOR_EVENTS_TO_FIRE);
Assert.IsTrue(m_iNotificationCount == 1, "Sensor Observer missed the Warmer Plate PE->PNE transition");

obCoffeeMaker.WarmerPlateStatus = WarmerPlateStatus.WARMER_EMPTY;
Thread.Sleep(I_WAIT_FOR_EVENTS_TO_FIRE);
Assert.IsTrue(m_iNotificationCount == 2, "Sensor Observer missed the Warmer Plate PNE->WE transition");

// and so on for all 6 transitions

Code is similar to that of BoilerEmpty event except that you raise an event whenever there is a change between last and current values
The test and the ListenForChanges method both are nearly exceeding a screenful.. but I’ll let it be for now. I don’t see more additions coming.. if they do I‘ll slice-n-extract methods.

Ok so now we have everything ready for the real deal.. CoffeeMaker. Lets begin with something simple.
Turn the page...