New to Telerik JustMock? Download free 30-day trial

Automocking

The automocking container makes Telerik JustMock even more appealing, due to out-of-box support for IoC. Developers do not need to find the appropriate auto mocking container and make it work.

Overview

Automocking allows the developer to create an instance of a class (the system under test) without having to explicitly create each individual dependency as a unique mock. The mocked dependencies are still available to the developer if methods or properties need to be arranged as part of the test.

For simple classes with few dependencies, automocking provides only marginal benefit. The real benefit comes with complex classes with multiple dependencies, or classes that change over time. Tests written for the methods in these classes typically do not need all of the dependencies explicitly mocked as part of the act or assertions, but they are required for class instantiation in arrange.

Automocking allows the developer to focus on the dependencies they care about for the specific test and essentially ignore the rest.

According to Single Responsibility, if a class has too many dependencies it should be refactored to be more concise and focused. Whether the class is left with the multiple dependencies, or gets refactored into smaller classes, automocking reduces the friction of changing unit tests. The tests that require specific mocks will still have those mocks accessible through the automocking container, and will dynamically adjust the instantiation of the system under test (SUT) based on the constructors requirements.

The JustMock MockingContainer uses the Ninject dependency injector to do the heavy lifting. However, as the MockingContainer holds all of the Ninjects functionalities it also expands them in a way to fit well inside TelerikJustMock. The final result is a mocking tool that uses the Ninject dependency injector for resolving dependences for a given class. As said, users will remain completely unaware of the underlying IOC container and there will be no reference of Ninject in their code whatsoever.

As MockingContainer derives from Ninject.StandardKernel, you can configure it just as you would configure the Ninject dependency injector. Visit the Ninject official page or the Ninject wiki in GitHub for further references.

Automocking Interfaces

Assume that we have the following code, to be tested:

public class ClassUnderTest 
{ 
    private IFirstDependency firstDep; 
    private ISecondDependency secondDep; 
    private IThirdDependency thirdDep; 
 
    public ClassUnderTest(IFirstDependency first, ISecondDependency second, IThirdDependency third) 
    { 
        this.firstDep = first; 
        this.secondDep = second; 
        this.thirdDep = third; 
    } 
 
    public IList<object> CollectionMethod() 
    { 
        var firstCollection = firstDep.GetList(); 
 
        return firstCollection; 
    } 
 
    public string StringMethod() 
    { 
        var secondString = secondDep.GetString(); 
 
        return secondString; 
    } 
 
    public void SetIntMethod(int value) 
    { 
        thirdDep.IntValue = value; 
    } 
} 
Public Class ClassUnderTest 
    Private firstDep As IFirstDependency 
    Private secondDep As ISecondDependency 
    Private thirdDep As IThirdDependency 
 
    Public Sub New(first As IFirstDependency, second As ISecondDependency, third As IThirdDependency) 
        Me.firstDep = first 
        Me.secondDep = second 
        Me.thirdDep = third 
    End Sub 
 
    Public Function CollectionMethod() As IList(Of Object) 
        Dim firstCollection = firstDep.GetList() 
 
        Return firstCollection 
    End Function 
 
    Public Function StringMethod() As String 
        Dim secondString = secondDep.GetString() 
 
        Return secondString 
    End Function 
 
    Public Sub SetIntMethod(ByVal value As Integer) 
        thirdDep.IntValue = value 
    End Sub 
End Class 

As you can see, our ClassUnderTest has two external dependencies:

public interface IFirstDependency 
{ 
    IList<object> GetList(); 
} 
 
public interface ISecondDependency 
{ 
    string GetString(); 
} 
 
public interface IThirdDependency 
{ 
    int IntValue { get; set; } 
} 
Public Interface IFirstDependency 
    Function GetList() As IList(Of Object) 
End Interface 
 
Public Interface ISecondDependency 
    Function GetString() As String 
End Interface 
 
Interface IThirdDependency 
    Property IntValue As Integer 
End Interface 

To test the class under test against certain scenarios you will have to mock the dependencies. One way to do this is to mock them one by one and arrange their behavior as shown below:

1.We create a mock object of FirstDependency and SecondDependency.

  1. We create a new instance of our ClassUnderTest with the mocked dependencies.

  2. We arrange the behavior of the dependencies and the CUT.

  3. We act.

  4. We assert our expectations.

    [TestMethod] 
    public void ShouldMockDependenciesWithoutContainer() 
    { 
        // Arrange 
        var firstDep = Mock.Create<IFirstDependency>(); 
        var secondDep = Mock.Create<ISecondDependency>(); 
        var thirdDep = Mock.Create<IThirdDependency>(); 
     
        var newInstance = new ClassUnderTest(firstDep, secondDep, thirdDep); 
     
        string expectedString = "Test"; 
        int expectedInt = 10; 
     
        Mock.Arrange(() => secondDep.GetString()).Returns(expectedString); 
     
        // Act 
        var actual = newInstance.StringMethod(); 
        newInstance.SetIntMethod(expectedInt); 
     
        // Assert 
        Assert.AreEqual(expectedString, actual); 
        Assert.AreEqual(expectedInt, thirdDep.IntValue); 
    } 
    
    <TestMethod()> 
    Public Sub ShouldMockDependenciesWithoutContainer() 
        ' Arrange 
        Dim firstDep = Mock.Create(Of IFirstDependency)() 
        Dim secondDep = Mock.Create(Of ISecondDependency)() 
        Dim thirdDep = Mock.Create(Of IThirdDependency)() 
     
        Dim newInstance = New ClassUnderTest(firstDep, secondDep, thirdDep) 
     
        Dim expectedString As String = "Test" 
        Dim expectedInt As Integer = 10 
     
        Mock.Arrange(Function() secondDep.GetString()).Returns(expectedString) 
     
        ' Act 
        Dim actual = newInstance.StringMethod() 
        newInstance.SetIntMethod(expectedInt) 
     
        ' Assert 
        Assert.AreEqual(expectedString, actual) 
        Assert.AreEqual(expectedInt, thirdDep.IntValue) 
    End Sub 
    

This will work for certain scenarios, but not for all of them. For example there will be scenarios where you will have more dependencies and all of them needing to be mocked. In these cases you will find the JustMock mocking container very handy. Next is how the previous example will look like using the Automocking feature:

  1. We create a MockingContainer from our ClassUnderTest.

  2. We arrange the behavior of the dependencies and the CUT.

  3. We act.

  4. We assert our expectations.

Import the Telerik.JustMock and Telerik.JustMock.AutoMock namespaces.

[TestMethod] 
public void ShouldMockDependenciesWithContainer() 
{ 
    // Arrange 
    var container = new MockingContainer<ClassUnderTest>(); 
 
    string expectedString = "Test"; 
    int expectedInt = 10; 
 
    container.Arrange<ISecondDependency>( 
       secondDep => secondDep.GetString()).Returns(expectedString); 
 
    // Act 
    var actualString = container.Instance.StringMethod(); 
    container.Instance.SetIntMethod(expectedInt); 
 
    // Assert 
    Assert.AreEqual(expectedString, actualString); 
    container.AssertSet<IThirdDependency>(thirdDep => thirdDep.IntValue = expectedInt); 
} 
<TestMethod()> 
Public Sub ShouldMockDependenciesWithContainer() 
    ' Arrange 
    Dim container = New MockingContainer(Of ClassUnderTest)() 
 
    Dim expectedString As String = "Test" 
    Dim expectedInt As Integer = 10 
 
    container.Arrange(Of ISecondDependency)(Function(secondDep) secondDep.GetString()).Returns(expectedString) 
 
    ' Act 
    Dim actualString = container.Instance.StringMethod() 
    container.Instance.SetIntMethod(expectedInt) 
 
    ' Assert 
    Assert.AreEqual(expectedString, actualString) 
    container.AssertSet(Of IThirdDependency)(Sub(thirdDep) thirdDep.IntValue = expectedInt) 
End Sub 

In this way, your test method stays more consistent and adding another dependency, won't break it's logic.

Another way to assert the arrangements is shown in the next example:

[TestMethod] 
public void ShouldAssertAllContainerArrangments() 
{ 
    // Arrange 
    var container = new MockingContainer<ClassUnderTest>(); 
 
    container.Arrange<ISecondDependency>( 
       secondDep => secondDep.GetString()).MustBeCalled(); 
    container.ArrangeSet<IThirdDependency>( 
        thirdDep => thirdDep.IntValue = Arg.AnyInt).MustBeCalled(); 
 
    // Act 
    var actualString = container.Instance.StringMethod(); 
    container.Instance.SetIntMethod(10); 
 
    // Assert 
    container.AssertAll(); 
} 
<TestMethod()> 
Public Sub ShouldAssertAllContainerArrangments() 
    ' Arrange 
    Dim container = New MockingContainer(Of ClassUnderTest)() 
 
    container.Arrange(Of ISecondDependency)(Function(secondDep) secondDep.GetString()).MustBeCalled() 
    container.ArrangeSet(Of IThirdDependency)(Sub(thirdDep) thirdDep.IntValue = Arg.AnyInt).MustBeCalled() 
 
    ' Act 
    Dim actualString = container.Instance.StringMethod() 
    container.Instance.SetIntMethod(10) 
 
    ' Assert 
    container.AssertAll() 
End Sub 

This style of assertion let's you focus on the arrange, as a container of your tests logic.

Elevated Automocking

Elevated Feature. Refer to this topic to learn more about the differences between both the commercial and free versions of Telerik JustMock.

The functionality of the JustMocks profiler enabled automocking feature is rather the same as the conceptual design of the automocking, as a whole.

Following this article, you will see examples that should explain how Elevated Automocking is used inside JustMock test methods.

To use Elevated Automocking you first need to go to elevated mode by enabling Telerik JustMock from the menu. How to Enable/Disable Telerik JustMock?

The first example shows how easily inheritance could be handled using this feature. Assume, we have the class below with its dependency:

public interface IAnimal 
{ 
    void Walk(); 
} 
 
public class Person : IAnimal 
{ 
    public void Walk() 
    { 
 
    } 
} 
 
public class PersonRepository 
{ 
    public PersonRepository(Person person) 
    { 
        this.person = person; 
    } 
 
    public void Walk() 
    { 
        (this.person as IAnimal).Walk(); 
    } 
 
    private readonly Person person; 
} 
Public Interface IAnimal 
    Sub Walk() 
End Interface 
 
Public Class Person 
Implements IAnimal 
    Public Sub Walk() Implements IAnimal.Walk 
 
    End Sub 
End Class 
 
Public Class PersonRepository 
    Public Sub New(person As Person) 
        Me.person = person 
    End Sub 
 
    Public Sub Walk() 
        TryCast(Me.person, IAnimal).Walk() 
    End Sub 
 
    Private ReadOnly person As Person 
End Class 

With JustMocks Elevated Automocking we are able to directly write the next test:

[TestMethod] 
public void ShouldAutoMockConcretedDependecies() 
{ 
    var container = new MockingContainer<PersonRepository>(); 
 
    container.Arrange<Person>(anml => anml.Walk()).MustBeCalled(); 
 
    container.Instance.Walk(); 
 
    container.Assert<Person>(anml => anml.Walk()); 
} 
<TestMethod> 
Public Sub ShouldAutoMockConcretedDependecies() 
    Dim container = New MockingContainer(Of PersonRepository)() 
 
    container.Arrange(Of Person)(Sub(anml) anml.Walk()).MustBeCalled() 
 
    container.Instance.Walk() 
 
    container.Assert(Of Person)(Sub(anml) anml.Walk()) 
End Sub 

This saves us the time of creating independent mock for our dependency, and further, the inheritance is preserved.

The second example shows how multiple dependencies of the same type could be managed with the TelerikJustMocks MockingContainer.

Note the following classes:

public class Account 
{ 
    public decimal Balance { get; set; } 
 
    public void Deposit(decimal amount) 
    { 
        throw new NotImplementedException(); 
    } 
 
    public void Withdraw(decimal amount) 
    { 
        throw new NotImplementedException(); 
    } 
} 
 
public class AccountService 
{ 
    public AccountService(Account fromAccount, Account toAccount) 
    { 
        this.fromAccount = fromAccount; 
        this.toAccount = toAccount; 
    } 
 
    public void TransferFunds(decimal amount) 
    { 
        if (fromAccount.Balance <= amount) 
        { 
            fromAccount.Withdraw(amount); 
            toAccount.Deposit(amount); 
        } 
    } 
 
    private readonly Account fromAccount; 
    private readonly Account toAccount; 
} 
Public Class Account 
    Public Property Balance() As Decimal 
        Get 
            Return m_Balance 
        End Get 
        Set 
            m_Balance = Value 
        End Set 
    End Property 
    Private m_Balance As Decimal 
 
    Public Sub Deposit(amount As Decimal) 
        Throw New NotImplementedException() 
    End Sub 
 
    Public Sub Withdraw(amount As Decimal) 
        Throw New NotImplementedException() 
    End Sub 
End Class 
 
Public Class AccountService 
    Public Sub New(fromAccount As Account, toAccount As Account) 
        Me.fromAccount = fromAccount 
        Me.toAccount = toAccount 
    End Sub 
 
    Public Sub TransferFunds(amount As Decimal) 
        If fromAccount.Balance <= amount Then 
            fromAccount.Withdraw(amount) 
            toAccount.Deposit(amount) 
        End If 
    End Sub 
 
    Private ReadOnly fromAccount As Account 
    Private ReadOnly toAccount As Account 
End Class 

Again, we are able to directly apply the next test method:

[TestMethod] 
public void ShouldTransferFundsBetweenTwoAccounts() 
{ 
    var container = new MockingContainer<AccountService>(); 
 
    decimal expectedBalance = 100; 
 
    container.Bind<Account>().ToMock().InjectedIntoParameter("fromAccount") 
        .AndArrange(x => Mock.Arrange(() => x.Balance).Returns(expectedBalance).MustBeCalled()) 
        .AndArrange(x => Mock.Arrange(() => x.Withdraw(expectedBalance)).MustBeCalled()); 
    container.Bind<Account>().ToMock().InjectedIntoParameter("toAccount") 
        .AndArrange(x => Mock.Arrange(() => x.Deposit(expectedBalance)).MustBeCalled()); 
 
    container.Instance.TransferFunds(expectedBalance); 
 
    container.Assert(); 
} 
<TestMethod> _ 
Public Sub ShouldTransferFundsBetweenTwoAccounts() 
    Dim container = New MockingContainer(Of AccountService)() 
 
    Dim expectedBalance As Decimal = 100 
 
    container.Bind(Of Account)().ToMock().InjectedIntoParameter("fromAccount") _ 
        .AndArrange(Sub(x) Mock.Arrange(Function() x.Balance).Returns(expectedBalance).MustBeCalled()) _ 
        .AndArrange(Sub(x) Mock.Arrange(Sub() x.Withdraw(expectedBalance)).MustBeCalled()) 
    container.Bind(Of Account).ToMock().InjectedIntoParameter("toAccount") _ 
        .AndArrange(Sub(x) Mock.Arrange(Sub() x.Deposit(expectedBalance)).MustBeCalled()) 
 
    container.Instance.TransferFunds(expectedBalance) 
 
    container.Assert() 
End Sub 

Here, you are able to arrange the behavior of the different Account dependencies, from the mocking container.

Note that, you are free to add more external arguments to the AccountService class, and this will not break the consistency of your previously created test methods.

In this article