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; 
    } 
} 

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; } 
} 

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); 
    } 

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); 
} 

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(); 
} 

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; 
} 

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()); 
} 

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; 
} 

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(); 
} 

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.