Using Mocking Frameworks To Help With Unit Testing UI Controls

One of the more common reasons that developers tell us of why they don’t unit test is “All of my application is visual controls with code behind. Refactoring all of that code to a .dll that can be united tested will take more time than it is worth.” While it is true that unit testing is easier if your application lives “in code” as a separate assembly, you can still use unit testing in a UI-heavy code base. By judiciously using a mocking framework, you can speed up the process even more.

Consider this form from a WinForm application written in VB.NET.

image

The grid view has the following code behind :

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click For counter = 0 To DataGridView1.RowCount - 1 If (DataGridView1.Rows(counter).Cells(11).FormattedValue) Then If (DataGridView1.Rows(counter).Cells(10).Value <> "") Then TextBox1.Text = FormatCurrency(TextBox1.Text - DataGridView1.Rows(counter).Cells(10).Value, 2) End If End If Next End Sub

 

The business logic is intermingled with the visual controls (TextBox1, DataGridView1, etc…). Is there a way to easily unit test this code? The answer is yes. Step one is to add a unit test project to the solution. Step two is to break the sub method into a function method. Once the methods have an input and an output, you can put a unit test on it. For example:

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click For counter = 0 To DataGridView1.RowCount - 1 Dim initialValue = TextBox1.Text Dim cell0 = DataGridView1.Rows(counter).Cells(11) Dim cell1 = DataGridView1.Rows(counter).Cells(10) TextBox1.Text = GetCalculatedValue(initialValue, cell0, cell1) Next End Sub Public Function GetCalculatedValue(initalValue As String, cell0 As DataGridViewCell, cell1 As DataGridViewCell) As String Dim returnValue As String = initalValue If (cell0.FormattedValue) Then If (cell1.Value <> "") Then initalValue = FormatCurrency(TextBox1.Text - cell1.Value, 2) End If End If Return initalValue End Function

And we can add a unit test like this:

image

[TestMethod] public void GetCalculatedValue_ReturnsExpected() { Form1 instance = new Form1(); String baseValue = "$10.00"; DataGridView gridView = new DataGridView(); gridView.Columns.Add("TEST1", "TEST1"); gridView.Columns.Add("TEST2", "TEST2"); gridView.Rows.Add(new DataGridViewRow()); gridView.Rows[0].Cells[0].Value = "$1.00"; gridView.Rows[0].Cells[1].Value = "$2.00"; DataGridViewCell cell0 = gridView.Rows[0].Cells[0]; DataGridViewCell cell1 = gridView.Rows[0].Cells[1]; var actual = instance.GetCalculatedValue(baseValue, cell0, cell1); var expected = "$8.00"; Assert.AreEqual(expected, actual); }

 

Although this test runs green, it is suboptimal because we have to standup lots of objects (DataGridView, Columns, DataGridRow) just to get to the class we are interested in, in this case DataGridViewCell. Instead of generating all of that superfluous code, there is a better way to set the state of only the class we want – enter Mocking frameworks. Mocking frameworks give us the ability to focus only on the subjects under test (SUT) while ignoring everything else.

But there is a catch. There are 2 types of mocking frameworks: ones that generate their code based on inspecting the types and ones that generate their code based on the compiled IL. The former group includes RhinoMocks and Moq . If you try and add Moq to this unit test project and generate a DataGridViewCell like this:

[TestMethod] public void GetCalculatedValue_ReturnsExpected() { Form1 instance = new Form1(); String baseValue = "$10.00"; var mock0 = new Mock<DataGridViewCell>(); mock0.SetupGet(dataGridViewCell => dataGridViewCell.Value).Returns("$1.00"); var mock1 = new Mock<DataGridViewCell>(); mock1.SetupGet(dataGridViewCell => dataGridViewCell.Value).Returns("$2.00"); var actual = instance.GetCalculatedValue(baseValue, mock0.Object, mock1.Object); var expected = "$8.00"; Assert.AreEqual(expected, actual); }

You will get an exception

image

 

Since we don’t control DataGridViewCell’s code, there is no way to change those properties to overidable/nonvirtual. As a general rule, you only use RhinoMocks/Moq on classes that you can control.

The other type of mocking framework (based on IL) can solve this problem. There are 2 commercial frameworks (JustMock, TypeMock) but they cost $399/year (as of this writing). There is a 3rd framework we can use and it is built into Visual Studio 2012+. It is called the Microsoft Fakes Framework. By adding this to your test project,

image

you can craft your unit test like so:

[TestMethod] public void GetCalculatedValue_ReturnsExpected() { Form1 instance = new Form1(); String baseValue = "$10.00"; using (ShimsContext.Create()) { var cell0 = new ShimDataGridViewCell(new StubDataGridViewCell()); cell0.FormattedValueGet = () => { return "$1.00"; }; var cell1 = new ShimDataGridViewCell(new StubDataGridViewCell()); cell1.ValueGet = () => { return "$2.00"; }; var actual = instance.GetCalculatedValue(baseValue, cell0, cell1); var expected = "$8.00"; Assert.AreEqual(expected, actual); } }

and get green. The downside of using Microsoft Fakes is that you need to re-generate the fakes if the code changes. This makes it ideal for faking external libraries that don’t change much (like ADO.NET) but not assemblies that are under active development.

Advertisements

Unit Testing F# Projects

I am a big believer of unit tests and as I write more and more code, I suffer what sociologists call “confirmation bias” whereby I keep finding more and more reasons to confirm that I am right.  But I am at the point where I don’t believe in developer documentation (sorry Sandcastle), reflector (sorry Redgate), code comments, or architectural diagrams.  I believe in the code, the whole code, and nothing but the code.  Or as Rasheed Wallace might say if he was a coder versus a professional basketball player: “Code Don’t Lie!”.

And the only code that tells you what a module is doing is the unit tests.  If you want to see how the module behaves, look at the green unit tests.  If you want to see how the module is supposed to behave but is not, look at the red unit tests.  If you want to see how the module might or might behave because the code is out of control, look for the non-existent unit tests.

So when I started writing code in F#, the unit tests went along for the ride.  F# folks will tell you to use the REPL to get your code working and/or use a unit test project in F#.  I don’t do either because:

1) The REPL is designed for quick prototyping, not for having a durable, cantonal example of module behavior. Having a full suite of unit tests gives you code coverage, tests at the build, and a fail-proof way of documenting the code’s behavior.

2) Most of the other developers I work with are CSharpers.  Having the unit tests in C# allows them to understand the behavior in a language in which they are familiar.  Since the tests need to communicate the working code’s intent, having that in a language they understand is critical.  They don’t have to understand F# to use a F# module.  Also, porting from C# in MSTest to NUnit in C# is a snap.

So when you add a C# Unit Test project to your solution that has a F# module you want to test, there are a couple of things you need to do.

1) Add a reference from the Unit Test Project to the F# Project (Right Click, Add Reference)

image

2) Add a reference to F#

image

3) If you are using type providers (and who doesn’t) and you have the connection string in the .config file of the working code project, add a .config file to the unit test project and copy over the connection string

image

Note that you code has to reflect that the connection string is being used in 2 different ways by the type provider, as explained in this post.  Your F# code needs to look like this:

  1. type internal SqlConnection = SqlEntityConnection<ConnectionStringName="azureData">
  2.  
  3.  
  4. type public RestaurantAnalysis () =
  5.     
  6.     let connectionString = ConfigurationManager.ConnectionStrings.["azureData"].ConnectionString;
  7.     member public x.GetScoresByMonth () =
  8.         SqlConnection.GetDataContext(connectionString).Restaurants
  9.             |> Seq.map(fun x -> x.InspectionDate.Value.Month, x.InspectionScore.Value)
  10.             |> Seq.groupBy(fun x -> fst x)
  11.             |> Seq.toList

4) Finally, you have to rebuild the F# project each time you want the unit tests to pick up changes.  That is different from a C# unit test project referencing a C# working code project.

Finally, not related to unit testing but too short for a blog post, if you are using the type providers (and who doesn’t) and you need to expose your classes publicly, you can’t use the SqlEntity provider – you need to use the SqlData provider.  The catch is that SqlData does not work with Azure Sql Storage as far as I can tell.  In my case, I used SqlEntity and exposed tuples and custom types publicly.  Not the best, but still better than using C# and Entity Framework…

F# and Unit Testing

Consider this code snippet in F#

  1. module Board =
  2.     let tiles = [|0 .. 39|]
  3.     let random = System.Random()
  4.  
  5.     let communityChest x =
  6.         let communityChestDraw = random.Next(1,17)
  7.         if communityChestDraw = 1 then
  8.             0
  9.         else if communityChestDraw = 2 then
  10.             10
  11.          else
  12.             x

 

I then went to create a unit test for the communityChest function when it hit me that I will get unpredictable behavior because I am getting a random number within the method body.  I made this same mistake when I created my windows phone 7 game where there combat engine was using a Random.Next() result.

Basically, I am repeating my mistakes across two languages.  The good news is that the solution is the same for both languages: I need to inject the result from Random.Next() into community chest.

  1. let communityChest x y =
  2.     if y = 1 then
  3.         0
  4.     else if y = 2 then
  5.         10
  6.      else
  7.         x

 

And then

  1. let move x y =
  2.     let communityChestDraw = random.Next(1,17)
  3.  
  4.     if x + y > 39 then
  5.         x + y – 40
  6.     else if x + y = 30 then
  7.         10
  8.     else if x + y = 2 then
  9.         communityChest 2 communityChestDraw
  10.     else if x + y = 7 then
  11.         chance 7
  12.     else if x + y = 17 then
  13.         communityChest 2 communityChestDraw
  14.     else if x + y = 22 then
  15.         chance 22
  16.     else if x + y = 33 then
  17.         communityChest 2 communityChestDraw
  18.     else if x + y = 36 then
  19.         chance 36
  20.     else
  21.         x + y

 

The other nice thing is I found the bug that was, well, bugging me.  The reason that 2 showed up the most was that I had copied and pasted 2 to be the results of all community chest runs.  I then changed the code to reflect the actual position of community chest:

  1. let move x y =
  2.     let communityChestDraw = random.Next(1,17)
  3.  
  4.     if x + y > 39 then
  5.         x + y – 40
  6.     else if x + y = 30 then
  7.         10
  8.     else if x + y = 2 then
  9.         communityChest 2 communityChestDraw
  10.     else if x + y = 7 then
  11.         chance 7
  12.     else if x + y = 17 then
  13.         communityChest 17 communityChestDraw
  14.     else if x + y = 22 then
  15.         chance 22
  16.     else if x + y = 33 then
  17.         communityChest 33 communityChestDraw
  18.     else if x + y = 36 then
  19.         chance 36
  20.     else
  21.         x + y

 

So now I can do my unit tests:

  1. [TestClass]
  2. public class SimulatorTests
  3. {
  4.     [TestMethod]
  5.     public void communityChestWithOne_ReturnsZero()
  6.     {
  7.         var result = Simulator.communityChest(2, 1);
  8.         Assert.AreEqual(0, result);
  9.     }
  10.  
  11.     [TestMethod]
  12.     public void communityChestWithTwo_ReturnsTen()
  13.     {
  14.         var result = Simulator.communityChest(2, 2);
  15.         Assert.AreEqual(10, result);
  16.     }
  17.  
  18.     [TestMethod]
  19.     public void communityChestWithThree_ReturnsTwo()
  20.     {
  21.         var result = Simulator.communityChest(2, 3);
  22.         Assert.AreEqual(2, result);
  23.     }
  24. }

 

And the tests run green:

image

I love being able to write C# tests and test F# code…

NInject Example

I started looking at NInject do handle the dependency injection that I normally do by hand.   To that end, I spun up the project that I used for my last foray into the world of dependency injection:

  1. public interface IAnimal
  2. {
  3.     void Talk();
  4.     void Eat();
  5. }

 

And

 

  1. public class Elephant: IAnimal
  2. {
  3.     public void Talk()
  4.     {
  5.         Console.WriteLine("Trumpet");
  6.     }
  7.  
  8.     public void Eat()
  9.     {
  10.         Console.WriteLine("Yummy Peanuts");
  11.     }
  12. }
  13.  
  14. public class Seal: IAnimal
  15. {
  16.     public void Talk()
  17.     {
  18.         Console.WriteLine("Ark Ark");
  19.     }
  20.  
  21.     public void Eat()
  22.     {
  23.         Console.WriteLine("Yummy Fish");
  24.     }
  25. }

 

Mow, instead of using Activator.CreateInstance, I am going to use NInject to do the mapping,  To that end, I installed NInject via NuGet

image

I then coded up the example for the on-line tutorial using the StandardKernal class like so

  1. static void Main(string[] args)
  2. {
  3.     IKernel kernel = new StandardKernel();
  4.     IAnimal animal = kernel.Get<Elephant>();
  5.     animal.Talk();
  6.     animal.Eat();
  7.     Console.ReadKey();
  8. }

 

and sure enough

image

So this is good stuff.  I think NInject and MOQ are my two favorite new tools in the toolbox…

InternalsVisibleTo

Dear Future Jamie:

When you want to test private methods, do this:

1) Change the scope from private to internal

2) Add this attribute to the namespace of the class that has the private method:

[assembly: InternalsVisibleTo(“NameSpace.Class.Tests”)]

3) Add this using statement to the class that has #2 in it:

using System.Runtime.CompilerServices;

 

Love,

Past Jamie

Unit Testing and the Microframework

So I started writing some real code to handle the PWM signals coming into the Netduino from a RC receiver.  The simple code that I had has quickly  morphed into a jumbled mess of spaghetti code:

image

I stopped writing code and decided that this ripe for some unit testing.  I added a unit test project to my solution but I got this:

image

Sure enough:

image

This is the same problem I had with my Windows Phone app.  Instead of giving up on unit testing (which is what I did with my WP app, and now I am regretting it), I decided to take a separate approach.  I first thought of using a testable .dll that has the code for the Netduino app but I ran into the same problem:

image

So I need to create a test harness for my code in the Microframework.  Fortunately, when I googled that on bing, I found this great article.

Instead of adding a reference to the Microframework, I Added As Link to the class I want to test:

image

I can then test the methods in the class.

The problem with this way of testing is that if the class under test references other assemblies or services, those assemblies need to be referenced in the testing project.  What happened is that my testing project quickly became bloated and violated the Law Of Demeter.

I wonder if MSFT will come out with a testing framework for both the Microframework and/or the PCLs…

Why .NET Developers Don’t Unit Test

Short answer: It’s Microsoft’s fault.

Long answer:

I am going to describe the journey of Well Intention Programmer (WIP).  He started writing software code in the mid-90s using this book:

image

and when .NET came out he slid over to C#

image

Along the way, he has written several highly-regarded programs that always exceed expectations and came in under-budget in the the 1st release but struggled in subsequent releases.  So the WIP decides to learn about how to improve his code quality to help him with the old code and to deliver more timely 2.x releases.  He picks up theses books:

imageimage

And  learns that he shouldn’t change a single line of code without covering unit tests.  Eager to try unit testing out, he opens up some legacy code and finds this:

public List<String> GetRegions()
{
    List<String> regions = new List<string>();
    String connectionString = @"Server=.;Database=Northwind;Trusted_Connection=True;";

    using(SqlConnection connection = new SqlConnection(connectionString))
    {
        String commandText = "Select * from Region";
        using (SqlCommand command = new SqlCommand(commandText, connection))
        {
            connection.Open();
            SqlDataReader reader = command.ExecuteReader();
            while (reader.Read())
            {
                regions.Add(reader["RegionDescription"].ToString());
            }
        }
    }

    return regions;
}

So the 1st thing the WIP might want to refactor is the hard-coded connection string in the function.  Microsoft has been telling the WIP for years that this string belongs in the .config file.  And it really does – not so much because you are going to swap out your DBMS (never happens) but because you should have environment-specific settings (that you don’t have on your local workstation).

To protect himself from the change, the WIP right clicks on the method name in VS2010

image

and he gets this out of the box test snippet like so:

[TestClass()]
public class NorthinwindFactoryTests
{
    [TestMethod()]
    public void GetRegionsTest()
    {
        NorthinwindFactory target = new NorthinwindFactory(); // TODO: Initialize to an appropriate value
        List<string> expected = null; // TODO: Initialize to an appropriate value
        List<string> actual;
        actual = target.GetRegions();
        Assert.AreEqual(expected, actual);
        Assert.Inconclusive("Verify the correctness of this test method.");
    }
}

He then alters it like so, using the Microsoft snippet to guide him.

[TestMethod()]
public void GetRegionsTest()
{
    NorthinwindFactory target = new NorthinwindFactory();
    Int32 expected = 4;
    Int32 actual = target.GetRegions().Count;
    Assert.AreEqual(expected, actual);
}

When he runs it, the test passes.

He then adds a reference to System.Configuration

image

The WIP comments out the initial line and then add a functionally equivalent line using a .config file:

//String connectionString = @"Server=.;Database=Northwind;Trusted_Connection=True;";
String connectionString = ConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString;

He re-runs the unit test and it still passes.  Felling good, he checks the code back into source.  Unfortunately, when the build goes to TEST/QA, it breaks because they have a special .config they use and that build server doesn’t have that database installed.  After a couple of hours of wrangling, WIP gets the correct .config into all environments and includes Northwind as part of the build.

WIP then reads that unit tests shouldn’t have external dependencies like databases and .config files.  To unit test right, he reads, he should use a Mocking Framework and he heard that MOQ is the best out there (editor comment: he’s right).  So WIP downloads MOQ and tries to mock his ConfigurationManager:

image

After a couple of hours of researching, he decides that the ConfigurationManager cannot be mocked.  Unwilling to give up on mocking, he fires up Rhino Mocks.  Alas:

image

Still unwilling to give up, he hits F12 on the Configuration Manager to see if it uses an interface that he can mock.  Perhaps an IConfigurationManager?  Nope.

image

so now the WIP has spent several of hours and he is nowhere with Unit Tests.

So forgetting ConfigurationManager, he decided to mock SqlConnection.  It starts out well enough:

image

and then

image

So that is good.  he can create a mock connection like so but he can’t use it without casting.

image

image

So he just can’t set the connection string.  This violation of the Law Of Demeter makes it really hard.  All he wanted to do is set a String value called ConnectionString and instead he has to learn about the internal workings of the DbConnection class.

So the WIP decided that he needs to re-write the entire method and use Entity Framework.  After all, EF is the new new data access technology and it must be mockable.  So the WIP goes out to this great blog post and is disappointed to learn that EF is even harder to mock than ADO.NET classes.

The WIP then turns his attention to his UI and tried to unit test/mock the visual data controls in ASP.NET.  Already half-expecting the answer, the WIP is not surprised

image

WIP probably gives up.

So whose fault is it?

The books?  Low. The point of the books are to teach the language, not good coding practices.  And basic books that don’t have a UI to demonstrate a concept (versus using unit tests) would take attention away from the primary focus – learning the language.  The most successful books have real working, albeit simple, UI projects.

The developer?  Low. WIP is hard-working, want to do the right thing, and are going to try unit testing.  He also has deadlines.

Unit Tests Advertising? Low.  True that unit tests have generally been forced upon dev teams by people better paid, with cooler job titles if not smarter than them.  Also, these smarter people also likely introduce different, convoluted techniques of hundreds of lines long or that use parts of the .NET language spec that only Phds understand to work around the fact that lots of the .NET APIs are untestable.

The projects?  Medium.  Many .NET projects do not have any business logic – they are simply CRUD UIs on top of a database.  Unit tests can’t tell you if the Sql string returns the expected result.  And in lots of projects, that is all it has.  Also, in lots of .NET projects, any logic that could be tested is intermingled with the untestable code.  In the example above, the assumption tha GetRegions() is testable is false.

The API?  Absolutely. Every major class in Microsoft’s data stack are un-mockable and therefore un-unit testable.   Would it really kill MSFT to have an interface for these classes because perhaps, just perhaps, the classes won’t be only used in the way that they were thought of 15-20 years ago?  I get that Microsoft has been dragging code and outdated APIs though the different versions of .NET and it has to be frustrating to them that they can’t introduce changes easily.  However, until Microsoft starts making the classes that everyone uses Mockable, unit testing will not take off.  And it is not just ADO.NET, WinForms, WebForms, System.IO, etc… all are un-mockable.

So some people might ask.  Why not use VS2012 MSFT mocks?  Well, that is a clown show.  It flies in the face of iterative development – every new object, regenerate your mocks.  Also, the syntax pales in comparison to MOQ.  It is a compensation for poor class design that has been dragged forward – interest on technical debt if you will…  I think Microsoft should change their APIs, not build tools to get around their API’s failings.