Tuesday, April 13, 2010

The Mocks are Mocking me.

A few years ago I heard about the idea of mock testing and tried to apply it to my code. I choose to use the DotNetMock framework because it worked in a way that I could get my head around. However, my approach begged a few questions as was a lot of work. It was pretty close to the older way of working with mocks where people code the mocks and the stubs and so forth, (for a good introduction of what that is all about see Martin Fowler's article
'Mocks aren't Stubs'. So now, I decide to refractor the code to improve performance and to do it with Visual Basic 2010 using the MSUnitTest framework. So I have already posted about converting from NUnit to MSUnitTest. So adding in the DotNetMock stuff should be a piece of cake, right? Just reference the DotNetMock.dll and away you go. Not so, I try that and I get an error in the tests.
Test method TestMasterList.TestAssemblies.TestGetNewCode threw exception:

System.TypeInitializationException: The type initializer for 'DotNetMock.Assertion' threw an exception. ---> System.SystemException:
Cannot find an appropriate test framework implementation.
At this point I search around for an alternative testing framework for Mock testing and the biggest buzz seems to be about
Rhino.Mocks and TypeMock however, the latter is a commercial product. So the problems are; most of the examples are in C#, they make extensive use of lambda expression and what I can find in vb use an older syntax for the mock code. Now, I know nearly nothing about lambda expressions, part of the reason for this exercise is to learn some of the new shiny stuff that has come out over the last 4 or 5 years by refactoring the code to take advantage of this stuff and get some improvement in performance. To do that I want to know my existing tests are working. So I try to learn Rhino.Mocks and start a new project to do it. I decide to implement a view model controller in windows forms with a passive view and the view communicating to the controller using events. The test is failing for reasons that are unclear to me and I have posted to the Google Group (aka Usenet) Rhino.Mocks with this post
So meanwhile while I try to learn Rhino.Mocks and lambda syntax what do I do. DotNetMock is defunct as far as I can tell and from what I have seen in Rhino and other mocking frameworks, it was a dead end approach anyway. However, I have code that uses that approach and I need to get those tests to run. So I decided to create my own replacement for the element of DotNetMock that I use. Essentially I used the DotNetMock.Mock class and the ExpectationCounter. When I created a mock class I inherited from the base DotNetMock.Mock class so that i could use the Verify method to determine that the expectations I had set had been fulfilled. Now expectations were set using the ExpectationCounter as a member level variable in Mock class.
To give an example; for the interface IFoo declared below


    Public Interface IFoo

       Sub SomeMethod()

    End Interface

In the DotNetMock style this would be implemented as a mock class thus;

    Public Class MockFoo

       Implements IFoo
       Private _ExpectSomeMethodCall as New ExpectationCounter("SomeMethod")



       Public Sub SetExpectationOnSomeMethod(ByVal expectedCalls as integer)

          _ExpectSomeMethodCall.Expect = expectedCalls

       End Sub

       Public Sub SomeMethod() Implements IFoo.SomeMethod

          _ExpectSomeMethodCall.Inc

       End Sub
    End Class

In this case the mock class would be injected into what ever class that uses it and when your test code would call the MockFoo.Verify method it would not throw an exception if the number of calls to the "SomeMethod" method matched the value set in the expectation. Now my problem was how to do this in a testable way that was generic and would not require a custom Verify method in every case of the Mock class in the test projects.
The answer was to create a custom ExpectationCounter class.


Public Class ExpectationCounter



    Private _p1 As String



    Sub New(ByVal p1 As String)

        _p1 = p1

        _receivedCalls = 0

    End Sub



    Property Expected As Integer



    Private _receivedCalls As Integer

    Sub Inc()

        _receivedCalls += 1

    End Sub



    Sub Verify()

        If Me.Expected = 0 Then Throw New ExpectationException(String.Format("No expectations set for '{0}'", _p1))

        If _receivedCalls <> Me.Expected Then



            Throw New ExpectationException(String.Format("Expected calls for '{0}' did not occur, Expected {1} got {2}", _p1, Me.Expected, _receivedCalls))



        End If

    End Sub



End Class



and a Mock Class
Imports System.Reflection



<clscompliant(true)>

Public Class Mock



    Public Sub Verify()

        Dim ex() As FieldInfo

        Dim isAnExpectationFieldPresent As Boolean = False

        ex = Me.GetType.GetFields(BindingFlags.NonPublic Or BindingFlags.Instance)

        If ex.Length <= 0 Then Throw New ExpectationException("No expectation fields set")



        For Each expectations As FieldInfo In ex

            If expectations.GetValue(Me).GetType.ToString = "ArdoughterSoftware.MockFramework.ExpectationCounter" Then

                isAnExpectationFieldPresent = True

                CType(expectations.GetValue(Me), ExpectationCounter).Verify()

            End If

        Next

        If Not isAnExpectationFieldPresent Then

            Throw New ExpectationException("No expectation Field set")

        End If

    End Sub



End Class

Now this should let me replace the DotNetMock with my own version and get my existing test to run. I would also expect that they would pass since they did the last time I ran tests on this code. Eventually once I figure out Rhino.Mocks I will replace all the DotNetMock/MyMocks with equivalent tests in that system So then I should be back to my original state but now in VS 2010. Then I can add additional tests to check on performance and then refractor from there.
Since Rhino.Mock is poorly documented in VB.NET I fully intend to post on my learning experiences and perhaps but a full journal of the development of the fantasy calendar project as future blog posts. It will make the project a bit more complicated that the application requirements might merit but in this case the requirements are to learn the mocking framework and the working fantasy calendar is a secondary target.

Fantasygrounds Unity: Importing an NPC from a text stat block.

  Fantasygrounds has been my primary VTT of choice for many years now. For most of that time I have been running games using official WoTC ...