Unit testing - some taunts

I am working with some outdated code that I need to write some unit tests. There is a data access method with the following signature.

Task ExecuteReaderAsync(string procedureName, Parameters procedureParameters, 
    params Action<System.Data.IDataReader>[] actions);

that there is an implementation in the class I'm testing, similar to this

private async Task<CustomObject> GetCustomObject(int id) 
{
    CustomObject obj = null;
    await db.ExecuteReaderAsync("nameOfProcedure", some parameters, 
    dr =>
    {
        obj = new CustomObject()
        {
            Prop1 = dr["Col1"],
            Prop2 = dr["Col2"]
        }
    }
    return obj;
}

What I'm struggling with is the ability to control the values ​​returned GetCustomObject. If I ExecuteReaderAsyncreally returned something that I could configure in this way.

mockDataAccess.Setup(x => x.ExecuteReaderAsync("nameOfProcedure", It.IsAny<Parameters>()))
    .Returns(Task.FromResult(new CustomeObject() { prop1 = "abc", prop2 = "def"};));

But the logic for indicating values ​​is one Action<IDataReader>that I do not control. I am wondering if there are any tricks that I could use to do what I want, i.e. control the value of the object returned GetCustomObject.

+4
1

[TestClass]
public class LegacyCodeTest {
    [TestMethod]
    public async Task TestExecuteReaderAsync() {
        //Arrange
        var mapping = new Dictionary<string, string> {
            { "Col1", "abc" },
            { "Col2", "def" }
        };

        var mockDataReader = new Mock<IDataReader>();
        mockDataReader
            .Setup(m => m[It.IsAny<string>()])
            .Returns<string>(col => mapping[col])
            .Verifiable();

        var mockDataAccess = new Mock<IDataAccess>();
        mockDataAccess
            .Setup(m => m.ExecuteReaderAsync("nameOfProcedure", It.IsAny<Parameters>(), It.IsAny<Action<System.Data.IDataReader>[]>()))
            .Returns(Task.FromResult<object>(null))
            .Callback((string s, Parameters p, Action<System.Data.IDataReader>[] a) => {

                if (a != null && a.Length > 0) {
                    a.ToList().ForEach(callback => callback(mockDataReader.Object));
                }

            })
            .Verifiable();


        var sut = new SUT(mockDataAccess.Object);

        //Act
        var actual = await sut.MUT(2);

        //Assert
        mockDataAccess.Verify();
        mockDataReader.Verify(m => m["Col1"]);
        mockDataReader.Verify(m => m["Col2"]);

        actual.Should()
            .NotBeNull()
            .And
            .Match<CustomObject>(c => c.Prop1 == mapping["Col1"] && c.Prop2 == mapping["Col2"]);

    }

    public interface IDataAccess {
        Task ExecuteReaderAsync(string procedureName, Parameters procedureParameters, params Action<System.Data.IDataReader>[] actions);
    }

    public class Parameters { }

    public class CustomObject {
        public object Prop1 { get; set; }
        public object Prop2 { get; set; }
    }

    public class SUT {
        IDataAccess db;

        public SUT(IDataAccess dataAccess) {
            this.db = dataAccess;
        }

        public async Task<CustomObject> MUT(int id) {
            var result = await GetCustomObject(id);
            return result;
        }

        private async Task<CustomObject> GetCustomObject(int id) {
            CustomObject obj = null;
            await db.ExecuteReaderAsync("nameOfProcedure", null,
            dr => {
                obj = new CustomObject() {
                    Prop1 = dr["Col1"],
                    Prop2 = dr["Col2"]
                };
            });
            return obj;
        }
    }
}

Action<IDataReader>, , , , . , , .

var mapping = new Dictionary<string, string> {
    { "Col1", "abc" },
    { "Col2", "def" }
};

var mockDataReader = new Mock<IDataReader>();
mockDataReader
    .Setup(m => m[It.IsAny<string>()])
    .Returns<string>(col => mapping[col])
    .Verifiable();

,

.Callback((string s, Parameters p, Action<System.Data.IDataReader>[] a) => {

    if (a != null && a.Length > 0) {
        a.ToList().ForEach(callback => callback(mockDataReader.Object));
    }

})

, .

OP, . , .

+2

Source: https://habr.com/ru/post/1667566/


All Articles