Testing Your Application with JustMock

This topic will guide you through several simple steps to enable easier testing of your applications by using Telerik® JustMock. You will understand a simple principle called Arrange/Act/Assert and get familiar with core methods and properties from the framework, which are used in the most common testing scenarios.

Make sure to go through Step 1 - Installation and Setup and Step 2 - Using JustMock in Your Test Project to setup your environment and project before proceeding further. Step 3 - JustMock API Basics contains basic examples that this article extends.

To illustrate the use of JustMock in the next examples, we will use a sample warehouse and a dependent order object. The warehouse holds inventories of different products. An order contains a product and a quantity.

The warehouse interface and the order class look like this:

public delegate void ProductRemoveEventHandler(string productName, int quantity);

public interface Iwarehouse
{
    event ProductRemoveEventHandler ProductRemoved;

    string Manager { get; set; }

    bool HasInventory(string productName, int quantity);
    void Remove(string productName, int quantity);
}

public class Order
{
    public Order(string productName, int quantity)
    {
        this.ProductName = productName;
        this.Quantity = quantity;
    }

    public string ProductName { get; private set; }
    public int Quantity { get; private set; }
    public bool IsFilled { get; private set; }

    public void Fill(Iwarehouse warehouse)
    {
        if (warehouse.HasInventory(this.ProductName, this.Quantity))
        {
            warehouse.Remove(this.ProductName, this.Quantity);
        }
    }

    public virtual string Receipt(DateTime orderDate)
    {
        return string.Format("Ordered {0} {1} on {2}", this.Quantity, this.ProductName, orderDate.ToString("d"));
    }
}
Public Delegate Sub ProductRemovedEventHandler(productName As String, quantity As Integer)

Public Interface IWarehouse
    Event ProductRemoved As ProductRemovedEventHandler

    Property Manager() As String

    Function HasInventory(productName As String, quantity As Integer) As Boolean
    Sub Remove(productName As String, quantity As Integer)
End Interface

Public Class Order
    Public Sub New(productName As String, quantity As Integer)
        Me.ProductName = productName
        Me.Quantity = quantity
    End Sub

    Public Property ProductName() As String
        Get
            Return m_ProductName
        End Get
        Private Set(value As String)
            m_ProductName = value
        End Set
    End Property
    Private m_ProductName As String
    Public Property Quantity() As Integer
        Get
            Return m_Quantity
        End Get
        Private Set(value As Integer)
            m_Quantity = value
        End Set
    End Property
    Private m_Quantity As Integer
    Public Property IsFilled() As Boolean
        Get
            Return m_IsFilled
        End Get
        Private Set(value As Boolean)
            m_IsFilled = value
        End Set
    End Property
    Private m_IsFilled As Boolean

    Public Sub Fill(warehouse As IWarehouse)
        If warehouse.HasInventory(Me.ProductName, Me.Quantity) Then
            warehouse.Remove(Me.ProductName, Me.Quantity)
            IsFilled = True
        End If
    End Sub

    Public Overridable Function Receipt(orderDate As DateTime) As String
        Return String.Format("Ordered {0} {1} on {2}", Me.Quantity, Me.ProductName, orderDate.ToString("d"))
    End Function
End Class

Arrange Act Assert (AAA) is a pattern for arranging and formatting code in Unit Test methods. It is used in all samples shown in this documentation. Refer to the Arrange Act Assert topic to learn about AAA.

Methods

Get familiar with the JustMock basics such as how to create mock instance with Mock.Create<>, how to arrange with Mock.Arrange and how to assert with Mock.Assert in Step 3 - JustMock API Basics.

There are a number of additional handy methods that you can use to make your tests more complete and easy to write.

DoInstead

You can use the DoInstead method when you want to change the behavior of a method when it is called by replacing it with a custom action. Let's use the example from above to illustrate to use of DoInstead.

[TestMethod]
    public void DoInstead_TestMethod()
    {
        //Arrange
        var warehouse = Mock.Create<Iwarehouse>();
        var order = new Order("Camera", 2);

        bool called = false;
        Mock.Arrange(() => warehouse.HasInventory("Camera", 2)).DoInstead(() => called = true);

        //Act
        order.Fill(warehouse);

        //Assert
        Assert.IsTrue(called);
    }
<TestMethod()>
    Public Sub DoInstead_TestMethod()
        ' Arrange
        Dim order = New Order("Camera", 2)
        Dim warehouse = Mock.Create(Of IWarehouse)()

        Dim called As Boolean = False
        Mock.Arrange(Function() warehouse.HasInventory("Camera", 2)).DoInstead(Sub() called = True)

        ' Act
        order.Fill(warehouse)

        ' Assert
        Assert.IsTrue(called)
    End Sub

Put simple – we arrange that when the warehouse’s HasInventory method is called with parameters "Camera" and 2 we will execute the action "() => called = true" instead of calling the actual method.

Read more about DoInstead.

CallOriginal

In some cases you may want to arrange to call the original method implementation when it is called with a specific value and to call the mock with other values. For this you can use the CallOriginal method.

[TestMethod]
    public void CallOriginal_TestMethod()
    {
        //Arrange
        var order = Mock.Create<Order>(Behavior.CallOriginal, "Camera", 2);

        Mock.Arrange(() => order.Receipt(DateTime.Today)).CallOriginal();
        Mock.Arrange(() => order.Receipt(Arg.Matches<DateTime>(d => d > DateTime.Today))).Returns("Invalid DateTime");

        //Act
        var callWithToday = order.Receipt(DateTime.Today);
        var callWithDifferentDay = order.Receipt(DateTime.Today.AddDays(1));

        //Assert
        Assert.AreEqual("Ordered 2 Camera on " + DateTime.Today.ToString("d"), callWithToday);
        Assert.AreEqual("Invalid DateTime", callWithDifferentDay);
    }
<TestMethod()>
    Public Sub CallOriginal_TestMethod()
        'Arrange
        Dim order = Mock.Create(Of Order)(Behavior.CallOriginal, "Camera", 2)

        Mock.Arrange(Function() order.Receipt(Arg.Matches(Of DateTime)(Function(d) d > DateTime.Today))).Returns("Invalid DateTime")

        'Act
        Dim callWithToday = order.Receipt(DateTime.Today)
        Dim callWithDifferentDay = order.Receipt(DateTime.Today.AddDays(1))

        'Assert
        Assert.AreEqual("Ordered 2 Camera on " + DateTime.Today, callWithToday)
        Assert.AreEqual("Invalid DateTime", callWithDifferentDay)
    End Sub

In this example we arrange that when order.Receipt method is called with argument DateTime.Today, then the original method implementation should be called. But once the same method is called with a date later than DateTime.Today then we return "Invalid date".

DoNothing

For arranging a void call it is a good practice to explicitly mark the mock with `DoNothing. The method is basically syntactic sugar and does nothing, as the name suggests, but improves the readability of your code. Lets see it in practice.

Mock.ArrangeSet(() =>  warehouse.Manager = "John");
Mock.ArrangeSet(() =>  warehouse.Manager = "John").DoNothing();
Mock.ArrangeSet(Sub() warehouse.Manager = "John");
Mock.ArrangeSet(Sub() warehouse.Manager = "John").DoNothing();

The first and the second line are functionally the same, but specifying explicitly that setting this property returns nothing makes the code more readable.

Throws

The Throws method is used when you want to throw an exception for a particular method invocation. In the following example, we are throwing an invalid operation exception for trying to call warehouse.Remove with zero quantity.

[TestMethod]
    [ExpectedException(typeof(InvalidOperationException))]
    public void Throws_TestMethod()
    {
        // Arrange
        var order = new Order("Camera", 0);
        var warehouse = Mock.Create<Iwarehouse>();

        // Set up that the ware house has inventory of any products with any quantities.
        Mock.Arrange(() => warehouse.HasInventory(Arg.IsAny<string>(), Arg.IsAny<int>())).Returns(true);

        // Set up that call to warehouse.Remove with zero quantity is invalid and throws an exception.
        Mock.Arrange(() => warehouse.Remove(Arg.IsAny<string>(), Arg.Matches<int>(x => x == 0)))
                    .Throws(new InvalidOperationException());

        // Act
        order.Fill(warehouse);
    }
<TestMethod()>
    <ExpectedException(GetType(InvalidOperationException))>
    Public Sub Throws_TestMethod()
        ' Arrange
        Dim order = New Order("Camera", 0)
        Dim warehouse = Mock.Create(Of IWarehouse)()

        ' Set up that the ware house has inventory of any products with any quantities.
        Mock.Arrange(Function() warehouse.HasInventory(Arg.IsAny(Of String)(), Arg.IsAny(Of Integer)())).Returns(True)

        ' Set up that call to warehouse.Remove with zero quantity is invalid and throws an exception.
        Mock.Arrange(Sub() warehouse.Remove(Arg.IsAny(Of String)(), Arg.Matches(Of Integer)(Function(x) x = 0))).Throws(New InvalidOperationException())

        ' Act
        order.Fill(warehouse)
    End Sub

In this case we use the ExpectedException attribute from Microsoft.VisualStudio.TestTools.UnitTesting to verify that exception of type InvalidOperationException is thrown.

Matchers

Matchers let you ignore passing actual values as arguments used in mocks. Instead, they give you the possibility to pass just an expression that satisfies the argument type or expected value range. For example, if a method accepts string as a first parameter, you don’t need to pass a specific string like "Camera", instead you can use Arg.IsAny<string>().

There are 3 types of matchers supported in JustMock:

  1. Arg.IsAny<[Type]>();
  2. Arg.IsInRange([FromValue : int], [ToValue : int], [RangeKind])
  3. Arg.Matches(Expression> expression)

Let's look at each one of them in details.

Arg.IsAny();

We already used this matcher in one of our examples above.

    Mock.Arrange(() => warehouse.HasInventory(Arg.IsAny<string>(), Arg.IsAny<int>())).Returns(true);
    Mock.Arrange(Function() warehouse.HasInventory(Arg.IsAny(Of String)(), Arg.IsAny(Of Integer)())).Returns(True)

This matcher specifies that when the HasInventory method is called with any string as a first argument and any int as a second it should return true.

Arg.IsInRange(int from, int to, RangeKind range)

The IsInRange matcher lets us arrange a call for an expected value range. With the RangeKind argument we can specify whether the given range includes or excludes its boundaries.

For argument values ranging from 0 to 5, the following will return true:

    Mock.Arrange(() => foo.Echo(Arg.IsInRange(0, 5, RangeKind.Inclusive))).Returns(true);
    Mock.Arrange(Function() foo.Echo(Arg.IsInRange(0, 5, RangeKind.Inclusive))).Returns(True)

For argument values ranging from 1 to 4, the following will return true:

    Mock.Arrange(() => foo.Echo(Arg.IsInRange(0, 5, RangeKind.Exclusive))).Returns(true);
    Mock.Arrange(Function() foo.Echo(Arg.IsInRange(0, 5, RangeKind.Exclusive))).Returns(True)

Arg.Matches (Expression> expression)

This is the most flexible matcher and it allows you to specify your own matching expression. Let's illustrate it with a simple example:

    Mock.Arrange(() => foo.Echo(Arg.Matches<int>( x => x < 10)).Returns(true);
    Mock.Arrange(Function() foo.Echo(Arg.Matches(Of Integer)(Function(x) x < 10))).Returns(True)

With our expression (or predicate) x => x < 10 we specify that a call to foo.Echo with an argument less than 10 should return true.

Properties

In the above examples we mock only methods, but you can also mock properties in the same way.

[TestMethod]
    public void MockingProperties_TestMethod()
    {
        // Arrange
        var warehouse = Mock.Create<Iwarehouse>();

        Mock.Arrange(() => warehouse.Manager).Returns("John");

        string manager = string.Empty;

        // Act
        manager = warehouse.Manager;

        // Assert
        Assert.AreEqual("John", manager);
    }
<TestMethod()>
    Public Sub MockingProperties_TestMethod()
        ' Arrange
        Dim warehouse = Mock.Create(Of IWarehouse)()

        Mock.Arrange(Function() warehouse.Manager).Returns("John")

        Dim manager As String = String.Empty

        ' Act
        manager = warehouse.Manager

        ' Assert
        Assert.AreEqual("John", manager)
    End Sub

Additionally, you can assert for property set.

[TestMethod]
    [ExpectedException(typeof(StrictMockException))]
    public void MockingProperties_PropertySet_TestMethod()
    {
        // Arrange
        var warehouse = Mock.Create<Iwarehouse>(Behavior.Strict);

        Mock.ArrangeSet(() => warehouse.Manager = "John");

        // Act
        warehouse.Manager = "Scott";
    }
<TestMethod()> _
    <ExpectedException(GetType(StrictMockException))> _
    Public Sub MockingProperties_PropertySet_TestMethod()
        ' Arrange
        Dim warehouse = Mock.Create(Of IWarehouse)(Behavior.[Strict])

        Mock.ArrangeSet(Sub() warehouse.Manager = "John")

        ' Act
        warehouse.Manager = "Scott"
    End Sub

In the arrange step we set up that the warehouse manager can only be set to "John". But in the act step we set the manager to "Scott". That throws a mock exception. Have in mind that this will only work if you create your mock with StrictBehavior.

Another commonly used technique is to assert that setting a property to a specific value throws an exception. Let's arrange this:

[TestMethod]
    [ExpectedException(typeof(ArgumentException))]
    public void MockingProperties_PropertySet_Throws_TestMethod()
    {
        // Arrange
        var warehouse = Mock.Create<Iwarehouse>();

        Mock.ArrangeSet(() => warehouse.Manager = "John").Throws<ArgumentException>();

        // Act
        // that's ok
        warehouse.Manager = "Scott";

        // but that would throw an ArgumentException
        warehouse.Manager = "John";
    }
<TestMethod()> 
<ExpectedException(GetType(ArgumentException))> _
    Public Sub MockingProperties_PropertySet_Throws_TestMethod()
        ' Arrange
        Dim warehouse = Mock.Create(Of IWarehouse)()

        Mock.ArrangeSet(Sub() warehouse.Manager = "John").Throws(Of ArgumentException)()

        ' Act
        ' that's ok
        warehouse.Manager = "Scott"

        ' but that would throw an ArgumentException
        warehouse.Manager = "John"
    End Sub

Here we used the Throws method discussed above to indicate that an exception should be thrown if the warehouse.Manager is set to "John".

Events

The method Raises allows you to raise an event when a method is called and to pass specific event arguments. Returning on our warehouse example, we may want to raise the ProductRemoved event once the Remove method is called.

[TestMethod]
    public void RaisingAnEvent_TestMethod()
    {
        // Arrange
        var warehouse = Mock.Create<Iwarehouse>();

        Mock.Arrange(() => warehouse.Remove(Arg.IsAny<string>(), Arg.IsInRange(int.MinValue, int.MaxValue, RangeKind.Exclusive)))
            .Raises(() => warehouse.ProductRemoved += null, "Camera", 2);

        string productName = string.Empty;
        int quantity = 0;

        warehouse.ProductRemoved += (p, q) => { productName = p; quantity = q; };

        // Act
        warehouse.Remove(Arg.AnyString, Arg.AnyInt);

        // Assert
        Assert.AreEqual("Camera", productName);
        Assert.AreEqual(2, quantity);
    }
Here in the arrange step we set up that once the warehouse’s Remove method is called we will raise the ProductRemoved event with parameters "Camera" and 2.

Wrapper Of Framework Assert

In the examples in this topic we have used the framework assertion that is available when a reference to the Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll is added to the project. In most of the examples in the further topics in the documentation a wrapper of the framework assert that exposes xUnit alike methods is used.

With the following using directive using FrameworkAssert = Microsoft.VisualStudio.TestTools.UnitTesting.Assert; the wrapper is defined as:

public static class Assert
{
    public static Exception Throws<T>( Action action ) where T : Exception
    {
        Exception targetException = null;

        try
        {
            action();
            FrameworkAssert.Fail( "No Expected " + typeof( T ).FullName + " was thrown" );
        }
        catch ( T ex )
        {
            targetException = ex;
        }
        return targetException;
    }

    public static void NotNull( object value )
    {
        FrameworkAssert.IsNotNull( value );
    }

    public static void Null( object value )
    {
        FrameworkAssert.IsNull( value );
    }

    public static void Equal<T>( T expected, T actual )
    {
        FrameworkAssert.AreEqual( expected, actual );
    }

    public static void NotEqual<T>( T notExpected, T actual )
    {
        FrameworkAssert.AreNotEqual( notExpected, actual );
    }

    public static void True( bool condition )
    {
        FrameworkAssert.IsTrue( condition );
    }

    public static void False( bool condition )
    {
        FrameworkAssert.IsFalse( condition );
    }

    public static void Same( object expected, object actual )
    {
        FrameworkAssert.AreSame( expected, actual );
    }
}

Additionally, with JustMock installed you receive a sample project that uses this wrapper of the framework assertion. Refer to the project for further information on how to use the Assert wrapper in your tests.

See Also

Is this article helpful? Yes / No
Thank you for your feedback!

Give article feedback

Tell us how we can improve this article

close
Dummy