I’ve written before about the process of writing the first unit test. I want to give an example of how you’re actually doing it.
What do I want to test
Let’s start with the canonical example: The closing form. Let’s say I have a Windows form. And I want to test what happens when I close it. Here’s the code for the closing event:
private void IsolatorTestForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (IsDirty)
{
var result = MessageBox.Show("Do you really want to close the window?",
"Confirm Closing",
MessageBoxButtons.OKCancel);
e.Cancel = (result == DialogResult.Cancel);
}
}
public bool IsDirty
{
get { throw new NotImplementedException(); }
}
So let’s start. The scenario I want to test is what happens when I close the form, after data has changed in the form and the user decided not to close the form. If you look closely, you can identify two more scenario to test – can you identify them?
Ok, first step: naming. Here’s the test name:
[TestMethod]
public void WhenClosing_DataHasChangedAndUserChoseToCancel_DontCloseForm()
{
// Arrange
// Act
// Assert
}
Arrange Act Assert in action
The name consists of three parts: What I’m testing, the specific scenario, and the expected result, all separated by underscores. Next I’m going to fill in the rest of my test, inside the Act and Assert parts.
[TestMethod]
public void WhenClosing_DataHasChangedAndUserChoseToCancel_DontCloseForm()
{
// Arrange
var form = new IsolatorTestForm();
// Act
form.Show();
form.Close();
// Assert
Assert.IsTrue(form.Visible);
}
Technically, creating the form object is part of the Act, but to be consistent with the next steps, I’ll leave it in the Arrange part, knowing the real story.
Ok, we have a test. Let’s run it. What happens?

And comes the exception
We get an exception, thrown from IsDirty. To circumvent that, we’ll add a statement to our Arrange that deals with this. In our scenario, IsDirty should be True, since it reflects that the data has changed. The test now looks like this:
[TestMethod]
public void WhenClosing_DataHasChangedAndUserChoseToCancel_DontCloseForm()
{
// Arrange
var form = new IsolatorTestForm();
Isolate.WhenCalled(() => form.IsDirty).WillReturn(true);
// Act
form.Show();
form.Close();
// Assert
Assert.IsTrue(form.Visible);
}
Let’s run the test again. This time, the test hangs. Well, not really. There’s a message box somewhere waiting for someone to press the buttons. This comes from the event handler as well.

Obviously we don’t want message boxes popping up in our automated tests. In our scenario, the user decided to press Cancel, so we’re going to add a statement for that. The test now looks like this:
[TestMethod]
public void WhenClosing_DataHasChangedAndUserChoseToCancel_DontCloseForm()
{
// Arrange
var form = new IsolatorTestForm();
Isolate.WhenCalled(() => form.IsDirty).WillReturn(true);
Isolate.WhenCalled(()=> MessageBox.Show(null,null,MessageBoxButtons.OK)).WillReturn(DialogResult.Cancel);
// Act
form.Show();
form.Close();
// Assert
Assert.IsTrue(form.Visible);
}
Note that I picked the correlating overload of MessageBox.Show inside the event handler, and I gave the compiler enough to approve my code. Since I don’t care about the arguments when I change behavior, I can pass whatever I want, as long as the compiler is happy.
Let’s run the test again. Is third time the charm? YES!! The test passes! Play Ode To Joy!
This iterative scenario works. We start with what we want to test, and the bare-bones test, including the assertion. With every iteration, we bypass another problem, and we go back to the scenario we want to test. We end up with a working test. It’s also a good way to learn Isolator’s APIs.
Try it. I’d like to hear about your experience.


