简体   繁体   English

如何使用moq模拟方法调用

[英]how to mock a method call using moq

My unit testing method is as follows 我的单元测试方法如下

[Test]
public void TrackPublicationChangesOnCDSTest()
{
    //Arrange
    // objDiskDeliveryBO = new DiskDeliveryBO();            

    //Act
    var actualResult = objDiskDeliveryBO.TrackPublicationChangesOnCDS();

    //Assert 
    var expectedZipName = 0;
    Assert.AreEqual(expectedZipName, actualResult);
}

The Actual method TrackPublicationChangesOnCDS in BO is as follows BO中的实际方法TrackPublicationChangesOnCDS如下

public int TrackPublicationChangesOnCDS()
{

    var resultFlag = -1;

    try
    {

        string pubUpdateFileCDSPath = CommonCalls.PubUpdateFileCDSPath;
        string pubUpdateFileLocalPath = CommonCalls.PubUpdateFileLocalPath;


        if (File.Exists(pubUpdateFileCDSPath))
            File.Copy(pubUpdateFileCDSPath, pubUpdateFileLocalPath, true);

        if (File.Exists(pubUpdateFileLocalPath))
        {

            string[] pubRecords = File.ReadAllLines(pubUpdateFileLocalPath);

            var pubRecordsExceptToday = pubRecords.Where(p => !p.Trim().EndsWith(DateTime.Now.ToString("dd/MM/yy"))).ToList();

            resultFlag = new DiskDeliveryDAO().TrackPublicationChangesOnCDS(pubRecordsExceptToday);

            File.WriteAllText(pubUpdateFileLocalPath, string.Empty);

            string[] pubRecordsCDS = File.ReadAllLines(pubUpdateFileCDSPath);
            var pubRecordsTodayCDS = pubRecordsCDS.Where(p => p.Trim().EndsWith(DateTime.Now.ToString("dd/MM/yy"))).ToList();
            File.WriteAllLines(pubUpdateFileCDSPath, pubRecordsTodayCDS);

        }

        return resultFlag;
    }
    catch (Exception)
    {

        return -1;
    }

}

I want to mock the method call DiskDeliveryDAO().TrackPublicationChangesOnCDS(pubRecordsExceptToday); 我想模拟方法调用DiskDeliveryDAO().TrackPublicationChangesOnCDS(pubRecordsExceptToday);

How Can I achieve this ? 我该如何实现? I am not getting enough examples online . 我在网上没有得到足够的例子。 I am using Moq library. 我正在使用Moq库。 Can someone help ? 有人可以帮忙吗?

Current code is too tightly coupled to implementation concerns to make it easy to test in isolation. 当前的代码与实现问题过于紧密地耦合在一起,以致于很难单独进行测试。

Reviewing the method under test revealed the following dependencies that were abstracted 回顾测试中的方法,发现以下抽象的依赖关系

public interface ICommonCalls {
    string PubUpdateFileCDSPath { get; }
    string PubUpdateFileLocalPath { get; }
}

public interface IDiskDeliveryDAO {
    int TrackPublicationChangesOnCDS(List<string> pubRecordsExceptToday);
}

public interface IFileSystem {
    bool Exists(string path);
    void Copy(string sourceFilePath, string destinationFilePath, bool overwrite);
    string[] ReadAllLines(string path);
    void WriteAllText(string path, string contents);
    void WriteAllLines(string path, IEnumerable<string> contents);
}

Their respective implementations would wrap/implement the desired functionality in production. 它们各自的实现将在生产中包装/实现所需的功能。

The abstractions would now allow the method under test to be refactored as below. 现在,抽象将允许按以下方式重构被测方法。

public class DiskDeliveryBO {
    readonly ICommonCalls CommonCalls;
    readonly IDiskDeliveryDAO diskDeliveryDAO;
    readonly IFileSystem File;

    public DiskDeliveryBO(ICommonCalls CommonCalls, IDiskDeliveryDAO diskDeliveryDAO, IFileSystem File) {
        this.CommonCalls = CommonCalls;
        this.diskDeliveryDAO = diskDeliveryDAO;
        this.File = File;
    }

    public int TrackPublicationChangesOnCDS() {

        var resultFlag = -1;

        try {

            string pubUpdateFileCDSPath = CommonCalls.PubUpdateFileCDSPath;
            string pubUpdateFileLocalPath = CommonCalls.PubUpdateFileLocalPath;


            if (File.Exists(pubUpdateFileCDSPath))
                File.Copy(pubUpdateFileCDSPath, pubUpdateFileLocalPath, true);

            if (File.Exists(pubUpdateFileLocalPath)) {

                string[] pubRecords = File.ReadAllLines(pubUpdateFileLocalPath);

                var pubRecordsExceptToday = pubRecords.Where(p => !p.Trim().EndsWith(DateTime.Now.ToString("dd/MM/yy"))).ToList();

                resultFlag = diskDeliveryDAO.TrackPublicationChangesOnCDS(pubRecordsExceptToday);

                File.WriteAllText(pubUpdateFileLocalPath, string.Empty);

                string[] pubRecordsCDS = File.ReadAllLines(pubUpdateFileCDSPath);
                var pubRecordsTodayCDS = pubRecordsCDS.Where(p => p.Trim().EndsWith(DateTime.Now.ToString("dd/MM/yy"))).ToList();
                File.WriteAllLines(pubUpdateFileCDSPath, pubRecordsTodayCDS);
            }

            return resultFlag;
        } catch (Exception) {

            return -1;
        }
    }
}

Note how not much has actually changed in the method itself apart from changing the tight coupling of new DiskDeliveryDAO() to the inject dependency. 请注意,除了将new DiskDeliveryDAO()与注入依赖项的紧密耦合更改之外,方法本身实际上没有多少更改。

Now the class is more flexible and can be tested in isolation where you have complete control of the dependencies and their behavior. 现在,该类更加灵活,可以在完全控制依赖项及其行为的情况下进行隔离测试。

public class DiskDeliveryBOTests {
    [Test]
    public void TrackPublicationChangesOnCDSTest() {
        //Arrange
        var expected = 0;
        var commonMock = new Mock<ICommonCalls>();
        //...Setup commonMock desired behavior

        var daoMock = new Mock<IDiskDeliveryDAO>();
        //...Setup daoMock desired behavior
        daoMock
            .Setup(_ => _.TrackPublicationChangesOnCDS(It.IsAny<List<string>>())
            .Returns(expected);

        var fileMock = new Mock<IFileSystem>();
        //...Setup fileMock desired behavior

        var objDiskDeliveryBO = new DiskDeliveryBO(commonMock.Object, daoMock.Object, fileMock.Object);

        //Act
        var actualResult = objDiskDeliveryBO.TrackPublicationChangesOnCDS();

        //Assert             
        Assert.AreEqual(expected, actualResult);
    }
}

Check Moq Quickstart for more on how to setup the desired behavior on the mocks. 请查看Moq快速入门,以获取有关如何在模拟中设置所需行为的更多信息。

It is not possible to mock DiskDeliveryDAO().TrackPublicationChangesOnCDS(pubRecordsExceptToday) using moq as it is directly newing the object using concrete class. 无法使用moq来模拟DiskDeliveryDAO()。TrackPublicationChangesOnCDS(pubRecordsExceptToday),因为它使用具体类直接更新对象。 It is possible only when we have the concrete class implement an interface and DiskDeliveryDAO object should be injected through DiskDeliveryBO's constructor. 仅当我们有具体的类实现接口并且应该通过DiskDeliveryBO的构造函数注入DiskDeliveryDAO对象时才有可能。

var mockDeliveryDao = new Mock<DiskDeliveryDAO>();

mockDeliveryDao.Setup(o=>o.TrackPublicationChangesOnCDS(It.IsAny<List<string>>()).Returns(1);//or whatever flag you want

Now you need to pass the deliveryDao as a parameter to the constructor. 现在,您需要将deliveryDao作为参数传递给构造函数。 Use Dependency Injection instead of creating a new DeliveryDao() object in the code. 使用依赖注入,而不是在代码中创建新的DeliveryDao()对象。

That way your code will read something like: 这样,您的代码将读取如下内容:

    resultFlag = _diskDeliveryDao.TrackPublicationChangesOnCDS(pubRecordsExceptToday);

While your constructor would be setting the _diskDeliveryDao member variable. 而您的构造函数将设置_diskDeliveryDao成员变量。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM