N.T.C
N.T.C

Reputation: 668

how to fake a very complicated object for TDD in VB.NET

Let say I have a class called CIRCLE, and another called SQUARE. In each of those class, I have a public function called area. (to calculate the area of the circle, and the area of the square respectively.)

I have also a class iMath. and in this class, I have a function ADD

    Public Function ADD(byval c as CIRCLE, byval s as SQUARE) 
       Return c.area() + s.area()
    End Function 

Now I want to Unit test the ADD function. Obviously, for this very easy problem, I can easily create a circle object and a square object to Unit test my ADD function. However, let assume that my Circle object and Square object are very complicated objects, very hard to create a object, because they inherit and contains many other dependencies. In such case,

  1. How can I fake the CIRCLE and SQUARE objects ? (note: the CIRCLE and SQUARE classes don't have Public Sub New without any parameter in it)

  2. How can I fake the results of the area functions the CIRCLE and SQUARE objects (I just need a number to test my ADD function, and I don't care how the areas are calculated)

Upvotes: 2

Views: 281

Answers (2)

Alexander Beletsky
Alexander Beletsky

Reputation: 19831

You should rely on existing mocking framework, which exactly solves that problem. One of my favourite one is NSubsitute.

It could create mock for any any interface of class with virtual functions. And in general it's more preferable that creating of manual mocks.

Upvotes: 1

Steven Doggart
Steven Doggart

Reputation: 43743

If you make all of the members of the CIRCLE and SQUARE classes Overridable, then you can inherit them and override all the members with stubs, for instance:

Public Class Circle
    Public Overridable Function Area() As Integer
        ' Complicated logic
    End Function
End Class

Public Class MockCircle
    Inherits Circle

    Public Overrides Function Area() As Integer
        Return 10
    End Function
End Class

However, if the original CIRCLE class requires a bunch of difficult-to-create parameters in its constructor, then that doesn't help you any because the MockCircle class will still be required to call the base constructor.

The preferable solution is to use interfaces. Instead of having your ADD method accept a concrete CIRCLE object, have it ask for an object that implements an ICircle interface instead:

Public Interface ICircle
    Function Area() As Integer
End Interface

Public Class Circle
    Implements ICircle

    Public Function Area() As Integer Implements ICircle.Area
        ' Complicated logic
    End Function
End Class

Public Class MockCircle
    Implements ICircle

    Public Function Area() As Integer Implements ICircle.Area
        Return 10
    End Function
End Class

Public Class MyMath
    Public Function Add(c As ICircle, s As ISquare) As Integer
        Return c.Area() + s.Area()
    End Function
End Class

Now, it doesn't matter what the CIRCLE requires in its constructor because you have taken it entirely out of the equation. Now, you can give the ADD method either a CIRCLE object or a MockCircle object and it will work either way. The MockCircle object doesn't inherit from CIRCLE, so it doesn't share any of its complicated dependencies. This methodology actually has a convenient name too. It's called Dependency Injection (DI). If you are going to be doing a lot of unit testing, it would be well worth your time to do some research on DI. Ideally, the dependencies for the CIRCLE class would also all be done via interfaces as well, so then you could easily create even a CIRCLE object by giving it all mock objects for its dependencies as well.

I feel obligated to mention some surface issues with your code too. For consistency with the .NET framework and Microsoft standards, you should use PascalCase for all of your method and class names. So for instance, it should be Add rather than ADD, and it should be Circle and Square rather than CIRCLE and SQUARE. Also, the iMath class name should not start with the letter "i". Putting an "I" at the beginning of a type name, according to Microsoft standards, means that it is an interface, not a class. The last issue I see is that your ADD function does not specify a return type. You should always specify the return type for all functions. For instance, in my example, I changed it to return As Integer.

Upvotes: 2

Related Questions