Mocking Methods With Ref Arguments Using Moq Framework In C#
Hello,
Cheers!
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.
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); } }
Source Code: Mocking Methods With Ref Arguments
Cheers!
Comments
Post a Comment