The Humble Dialog (and famous musketeers)
I have read Jeremy’s Build you own CAB series (Build your own CAB Part #2 – The Humble Dialog Box
). Jeremy is building the series with the help of d’Artagnan the famous Musketeer wanna-be.
Due to both his pride and an urge to ingratiate himself with those he wished to join, d’Artagnan is challenged to a duel by three musketeers Athos, Porthos, and Aramis. d’Artagnan had a little surprise for his opponents. He did not divide his concerns, instead he embraced them, and found himself fighting all 3 together. The 3 started fighting with each other over who will fight d’Artagnan first, but they all ended up fighting Cardinal Richelieu’s guards, who threaten to arrest them because duels are forbidden by royal decree…
I am going to show you just how we can manage to unit test a Simple Dialog without separating concerns and overcome the forbidden decree that GUI is hard to test.
I will use Jeremy’s requirement:
If the user attempts to close the XYZ screen without saving any outstanding changes, a message box is displayed to warn the user that they are discarding changes. If the user wishes to retain the outstanding work, do not close the screen. The message box should not be shown if the data has not been changed.
private void SimpleForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (isDirty())
{
bool canClose = MessageBox.Show(“Ok to discard changes or cancel to keep working”, “Confirm”,MessageBoxButtons.OKCancel) == DialogResult.OK;
e.Cancel = !canClose;
}
}
Unlike Jeremy, MessageBox will be no problem at all to test, actually the tests are quite straight forward and will give you the developer the freedom to choose (and refactor) the code when needed.
Here are the tests:
[Test]
[VerifyMocks]
public void CloseTheScreenWhenTheScreenIsNotDirty()
{
SimpleForm testedDialog = new SimpleForm();
using (RecordExpectations record = RecorderManager.StartRecording())
{
testedDialog.isDirty(); // mocked
record.Return(false).RepeatAlways();
}
testedDialog.Show();
testedDialog.Close();
Assert.AreEqual(false, testedDialog.Visible);
}
[Test]
[VerifyMocks]
public void CloseTheScreenWhenTheScreenIsDirtyAndTheUserDecidesToDiscardTheChanges()
{
SimpleForm testedDialog = new SimpleForm();
using (RecordExpectations record = RecorderManager.StartRecording())
{
testedDialog.isDirty(); // mocked
record.Return(true).RepeatAlways();
MessageBox.Show(“whatever”); // mocked
record.Return(DialogResult.OK);
}
testedDialog.Show();
testedDialog.Close();
Assert.AreEqual(false, testedDialog.Visible);
}
[Test]
[VerifyMocks]
public void CloseTheScreenWhenTheScreenIsDirtyAndTheUserDecidesNOTToDiscardTheChanges()
{
SimpleForm testedDialog = new SimpleForm();
using (RecordExpectations record = RecorderManager.StartRecording())
{
testedDialog.isDirty(); // mocked
record.Return(true).RepeatAlways();
MessageBox.Show(“whatever”); // mocked
record.Return(DialogResult.Cancel);
}
testedDialog.Show();
testedDialog.Close();
Assert.AreEqual(true, testedDialog.Visible);
}
Cool Ah!, we mocked the unmockable MessageBox, we also mocked the SimpleForm.isDirty, we actually tested the logic that we needed, this makes the GUI very testable with no effort at all.
The mocking is done in the using block where all calls are mocked and the behavior is set. Verification that the expectations where called is done using the [VerifyMocks] attribute. We could also test the message that is being displayed on the message box, but that is another test.
You should of course separate the GUI class when it grows bigger, but your test will still pass even if you do separate the concerns! Unless you change the message box to one of your own, but you have the ability to really do Just In Time Design (YAGNI)
Just one more tip for those of you who will try this technique. It will be a good idea to mock MessageBox.Show in all cases, just in case the test fails-> we don?t want the tests to hang with the message box. Just use .RepeatAll or FailIfCalled to make sure that we don’t fail if the MessageBox is not shown.
3 Comments to “The Humble Dialog (and famous musketeers)”
Recent Posts
- Unacceptable: Unit testing will take 20 years to catch on
- The 4 reasons why we DIDN’T choose Oslo
- Typemock Academy Launch
- The First Rule to Software Craftsmanship
- Goal-driven Development
Categories
- .NET Tests
- Agile
- Code Integrity
- Community
- Debugging
- Fun
- Management for Geeks
- Marketing
- Product
- Release
- Reviews
- SharePoint
- TDD
- Time Management
- Uncategorized
- Unit Tests
Archives
- May 2010
- April 2010
- March 2010
- February 2010
- December 2009
- October 2009
- September 2009
- August 2009
- July 2009
- June 2009
- May 2009
- April 2009
- March 2009
- February 2009
- December 2008
- November 2008
- August 2008
- July 2008
- May 2008
- April 2008
- February 2008
- January 2008
- December 2007
- November 2007
- October 2007
- September 2007
- August 2007
- July 2007
- June 2007
- May 2007
- April 2007
- March 2007
- February 2007
- January 2007
- December 2006
- November 2006
- October 2006
- September 2006

[...] Oren Eini has posted Tools vs. Design about the Really Simple Dialog post. [...]
[...] The TypeMock front page has a link to Eli Lopian’s blog (he’s their CTO). I bring this up because one recent post demonstrates using TypeMock to test a form close event that throws up a confirm dialog. Now, I don’t know about you, but a MessageBox.Show() call is practically untestable as far as I can see. Wrap it in an interface? Ugh. You’d want a broader UI communication interface and I cringe as I consider implementing such a thing. [...]
Rimsky went look closer buy cytotec then announced estivities.