Try our conversational search powered by Generative AI!

Stefan Forsberg
Jul 13, 2010
  4572
(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 and the never-ending story of the missing globe!

I've worked with Optimizely CMS for 14 years, and there are two things I'm obsessed with: Link validation and the globe that keeps disappearing on...

Tomas Hensrud Gulla | Apr 18, 2024 | Syndicated blog

Visitor Groups Usage Report For Optimizely CMS 12

This add-on offers detailed information on how visitor groups are used and how effective they are within Optimizely CMS. Editors can monitor and...

Adnan Zameer | Apr 18, 2024 | Syndicated blog

Azure AI Language – Abstractive Summarisation in Optimizely CMS

In this article, I show how the abstraction summarisation feature provided by the Azure AI Language platform, can be used within Optimizely CMS to...

Anil Patel | Apr 18, 2024 | Syndicated blog

Fix your Search & Navigation (Find) indexing job, please

Once upon a time, a colleague asked me to look into a customer database with weird spikes in database log usage. (You might start to wonder why I a...

Quan Mai | Apr 17, 2024 | Syndicated blog