Reputation: 668
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,
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)
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
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
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