Testing

Testing Complex Systems

By Gigi Sayfan, November 05, 2012

Good design practices can save your system and your sanity

These two interfaces isolate the domain from the rest of the application and allow mocking the domain for testing purposes, as you'll soon see. The user interface state and logic are managed by the Presenter class (See Listing Two). The Presenter accepts in its constructor an IMainWindow and IMindReader reference, and it implements the IMainWindowEvents and IMindReaderEvents interface.

When the go button is pressed, it should start a mind reading session, reset the progress bar to 0, reset the text box to the generic message: "You are thinking of…" and disable the button.

When progress reports arrive via OnProgress(), it should update the progress bar.

When OnReadComplete() is called, it should display the new thought, update progress to 100%, and enable the go button.

The PresenterTest verifies this entire sequence with the help of two mock objects in a few lines:

[TestMethod]
public void Test()
{
_presenter.OnGoButtonClick();
// The presenter should first disable the button and in the end re-enable it.
CollectionAssert.AreEqual(new List<bool>() { false, true }, _mockWindow.EnableGoButtonCalls);
// The presenter should set the thought twice, first to the generic message and then to the test thought
CollectionAssert.AreEqual(new List<string>() { "You are thinking of...", "whatever" }, _mockWindow.SetThoughtCalls);
// The presenter should update the progress bar 5 times (initially to 0, finally to 100)
CollectionAssert.AreEqual(new List<int>() { 0, 25, 50, 75, 100 }, _mockWindow.UpdateProgressCalls);
}

When I ran this test, I discovered a bug  I forgot to reset the progress bar to 0 in the Presenter. This is exactly the type of bug that may slip through the cracks and get discovered only in production.

Here is the test setup that hooks up the real Presenter to the mock window and the mock mind reader:

Later, the test attaches the Presenter to it as a sink. When the Presenter calls the Read() method (in response to the simulated button click), the mock mind reader sends its canned progress reports via OnProgress() and finally calls OnReadComplete(). The Presenter calls the appropriate methods on the mock main window, which records everything. Finally, the test verifies that the correct methods were invoked by checking the mock window's recorded calls.

This whole setup took very little time to write. It allows full testing of the UI management state, without dealing with an actual hard-to-test UI, and can be extended or modified easily when the real UI changes (and it will, count on it).

The steps I applied to enable testing transcend .NET, WPF, and the user interface:

Access all dependencies via interfaces (IMainWindow, IThoughtReader).

Mock dependencies with simple mock objects that capture the state and flow you want to test.

Hook up the object/system under test to all its mocked dependencies.

Run the object/system through the test scenarios.

Verify the object/system behaves as expected.

Testing Networking Code

Networking has become pervasive. Today, people often invoke a Web service, where they used to add a library to their application or, god forbid, write some code themselves. Designing a safe, robust, and performant connected system is much more complicated than a standalone system. The reason is that you have to handle many more failure modes and a lot of stuff that is not related to your code functionality, such as security and authentication. The remote system might disappear, slow down, or change at any moment, including in the middle of sending data or halfway through a complicated handshake. The reverse is true if your system is the remote service. How do you support old clients? How do you make sure your system scales and is highly available? How do you make sure attackers don't steal your data or bring your system down? These are important concerns and require a lot of engineering. To make sure you've got it right, you have to be able to simulate and test all these scenarios.

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task.
However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

Video

This month's Dr. Dobb's Journal

This month,
Dr. Dobb's Journal is devoted to mobile programming. We introduce you to Apple's new Swift programming language, discuss the perils of being the third-most-popular mobile platform, revisit SQLite on Android
, and much more!