Donate

Mocking Methods With Ref Arguments Using Moq Framework In C#

Hello,

Here's a straightforward post on how to mock methods with arguments that are passed by reference using the Moq framework. First, we need to create a C# Class Library and Xunit projects in Visual Studio. Create two folders in the class libary project specifically Infrastructure and Models. The structure of the application resembles the image below.
Mocking Methods With Ref Arguments Using Moq Framework In C#
Add a class to hold a person's information Person.cs inside the models folder with properties such as SocialSecurityID, FirstName and etc. Only the StatusUpdate property is used in the test project.
public class Person
{
    public int SocialSecurityID { get; set; }
    public string FirstName { get; set; }
    public string MiddleName { get; set; }
    public string LastName { get; set; }
    public  string StatusUpdate { get; set; }

    public Person()
    {
        SocialSecurityID = 0;
        FirstName = string.Empty;
        MiddleName = string.Empty;
        LastName = string.Empty;
        StatusUpdate = string.Empty;
    }
}
Define an interface called IPersonDB inside the Infrastructre folder with a single method declaration called Save that returns an integer value and has a single argument of type Person that is passed by reference.
public interface IPersonDB
{
    int Save(ref Person person);
}
Next is to create a class that implements the IPersonDB interface. As for the method, I only updated the StatusUpdate of the person object and return 1 if save is successful. For real-world applications, this could be a method to save information to a database or any datasource.
public class PersonDB : IPersonDB
{
    public int Save(ref Person person)
    {
        person.StatusUpdate = "Person saved successfully.";
        return 1;
    }
}
Lastly, create a PersonProcessor class that has a SavePersonInfo() method that calls the PersonDB Save method. This is the method that will be tested in our Test Project class.
public class PersonProcessor
{
    private readonly IPersonDB _personDB;

    public PersonProcessor(IPersonDB personDB)
    {
        _personDB = personDB;
    }

    public bool SavePersonInfo(Person person)
    {
        int statusCode = _personDB.Save(ref person);

        return statusCode == 1;
    }
}
In your test project class, define two test methods that will mock the Save() method of IPersonDB interface. The first test will pass specific objects employeeOne and employeeTwo of Type Person with the ref keyword. While the second one uses the It.Ref<Person>.IsAny() with the Person class as TValue instead of concrete objects.
public class PersonTest
{
    [Fact]
    public void TestRefObjectInstance()
    {
        //arrange
        var employeeOne = new Person();
        var employeeTwo = new Person();
        var mockPersonDB = new Mock<IPersonDB>();

        //act
        mockPersonDB.Setup(x => x.Save(ref employeeOne)).Returns(1).Callback(() => employeeOne.StatusUpdate = "Person saved successfully.");
        mockPersonDB.Setup(x => x.Save(ref employeeTwo)).Returns(-1);
        var processor = new PersonProcessor(mockPersonDB.Object);
        var resultEmployeeOne = processor.SavePersonInfo(employeeOne);
        var resultEmployeeTwo = processor.SavePersonInfo(employeeTwo);

        //assert
        Assert.True(resultEmployeeOne);
        Assert.Equal("Person saved successfully.", employeeOne.StatusUpdate);
        Assert.False(resultEmployeeTwo);
    }

    [Fact]
    public void TestRefCompatibleType()
    {
        //arrange
        var employeeOne = new Person();
        var employeeTwo = new Person();
        var mockPersonDB = new Mock<IPersonDB>();

        //act
        mockPersonDB.Setup(x => x.Save(ref It.Ref<Person>.IsAny)).Returns(-1);
        var processor = new PersonProcessor(mockPersonDB.Object);
        var resultEmployeeOne = processor.SavePersonInfo(employeeOne);
        var resultEmployeeTwo = processor.SavePersonInfo(employeeTwo);

        //assert
        Assert.False(resultEmployeeOne);
        Assert.False(resultEmployeeOne);
    }
}



Cheers!

Comments

Donate

Popular Posts From This Blog

WPF CRUD Application Using DataGrid, MVVM Pattern, Entity Framework, And C#.NET

How To Insert Or Add Emojis In Microsoft Teams Status Message

TypeScript Error Or Bug: The term 'tsc' is not recognized as the name of a cmdlet, function, script file, or operable program.