Calling all developers! We invite you to provide your input on Feature Experimentation by completing this brief survey.

 

Stefan Forsberg
Jul 13, 2010
  4693
(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
Level Up with Optimizely's Newly Relaunched Certifications!

We're thrilled to announce the relaunch of our Optimizely Certifications—designed to help partners, customers, and developers redefine what it mean...

Satata Satez | Jan 14, 2025

Introducing AI Assistance for DBLocalizationProvider

The LocalizationProvider for Optimizely has long been a powerful tool for enhancing the localization capabilities of Optimizely CMS. Designed to ma...

Luc Gosso (MVP) | Jan 14, 2025 | Syndicated blog

Order tabs with drag and drop - Blazor

I have started to play around a little with Blazor and the best way to learn is to reimplement some old stuff for CMS12. So I took a look at my old...

Per Nergård | Jan 14, 2025

Product Recommendations - Common Pitfalls

With the added freedom and flexibility that the release of the self-service widgets feature for Product Recommendations provides you as...

Dylan Walker | Jan 14, 2025