Stefan Forsberg
Jul 13, 2010
  4617
(0 votes)

Design principles and testing – part 5

We’ve been talking about various design principles in the last few posts.  So how does this relate to (unit) testing? In a recent talk I attended by Michael Feathers one of the many good points he made was this:

Design your application in a good way makes it testable. Making your code testable doesn’t necessarily make your design good.

So, let’s look at an example to clarify why this is so. Imagine we have a class that has a public method which in turn uses some private methods to do whatever the method needs. If you want to test those private methods you quickly realize you can’t since they’re private (I know there are techniques and products to get around this but if you’re using them for anything else than testing a large brownfield app you’re doing it wrong). When you notice that you can’t really test your application the way it’s designed right now this should be sort of a warning to you that your design is probably flawed.

Maybe those private methods are actually doing something not really related to your class and you’re violating SRP. Perhaps extracting those methods to a class (which in itself is public and testable) could be the solution. Another alternative would be to just change those private methods to public and go ahead with the testing. Notice here that both these approaches leads to you being able to write your tests but in terms of good design I really wouldn’t recommend alternative number 2.

Remember (and this can be somewhat of a pain in the beginning): testing isn’t and shouldn’t be hard. If it is it usually something else that makes it hard, either your design or perhaps the framework you’re using.

 

Writing some tests for our original code

Let’s look at the original version of our MainBody formatting method.

   1: protected void SaveClick(object sender, EventArgs e)
   2: {
   3:     var newMainBody = NewMainBody.Text
   4:         .Replace(Environment.NewLine, "<br />");
   5:  
   6:     var writablePage = CurrentPage.CreateWritableClone();
   7:  
   8:     writablePage.Property["MainBody"].Value = newMainBody;
   9:  
  10:     DataFactory.Instance.Save(writablePage, SaveAction.Publish);
  11: }

This code was places inside a code behind file that inherits from EPiServers TemplatePage class. Ignoring for the moment what we’ve learned about SRP and OCP and say that we want to test that the class correctly replaces newline with br.

Regardless of what framework you’re using for testing (I’m using NUnit here) the basic flow is more or less the same. You initialize some state (Arrange), you call your methods (Act) and finally verify your expectations (Assert).

So we create a new class library, add a reference to our web project and to the NUnit framework. With that in place we start to write the code and the first “problem” arises somewhere around here

   1: [Test]
   2: public void SaveClick_replaces_NewLine_with_br()
   3: {
   4:     // Arrange            
   5:     var defaultPage = new EPiServer.Templates.Default();
   6: }

It’s hard to tell by the code, but to create an instance of the Default page we need to add some EPiServer references as well as one to System.Web. It's feels slightly odd since we really only want to test some text replacement, but let’s play along for now.

When we want to call the SaveClick method we realize it’s protected so we can’t reach it. Hmm ok, so let’s make it public. Then we realize that we need some sort of… We could continue down this road but it basically just leads to heartaches.

A lot of people (yours truly included) in this situation think something along the lines of “god, testing is so hard and I have to make a lot of changes to my code that doesn’t make sense just to be able to test it”.

 

Writing tests for our refactored code

The case of testing our method that replaces newline with br could look something like this

   1: [TestMethod]
   2: public void MainBodyFormaterNewLine_String_With_NewLine_Returns_Same_String_With_Br()
   3: {
   4:     // Arrange
   5:     var stringWithNewLine = string.Concat("Hello", Environment.NewLine, "World");
   6:     var expectedResult = "Hello<br />World";
   7:     
   8:     // Act
   9:     var result = new MainBodyFormaterNewLine().Format(stringWithNewLine);
  10:  
  11:     // Assert
  12:     Assert.AreEqual(expectedResult, result);
  13: }

Since our method only does one thing it’s very easy to test and we only have to worry about things that concerns the method we want to test.

image

And this is the result when running the test (using ReSharpers testrunner). Pretty ey?

In the next post I’ll give some tips and concrete examples of problematic areas to test and what you can do to get around it.

Jul 13, 2010

Comments

Please login to comment.
Latest blogs
Optimizely's personalized product recommendations on Product Details Page (PDP) 

With the rise of AI and its integration into online shopping, personalization has become the cornerstone of an enhanced customer experience....

Hetaxi | Sep 20, 2024

keep special characters in URL

When creating a page, the default URL segment validation automatically replaces special characters with their standard equivalents (e.g., "ä" is...

K Khan | Sep 19, 2024

Streamlining Marketing Success: The Benefits for Optimizely One with Perficient

As an Optimizely expert, I eagerly anticipate this time of year due to the exciting Optimizely events happening worldwide. These include Opticon, t...

Alex Harris - Perficient | Sep 17, 2024 | Syndicated blog

Creating an Optimizely Addon - Packaging for NuGet

In   Part One   and   Part Two   of this series; I covered topics from having a great idea, solution structure, extending the menus and adding...

Mark Stott | Sep 16, 2024