簡體   English   中英

Moq:使用模擬參數設置通用方法

[英]Moq: setup a generic method with mocked parameters

我一直在嘗試為我的通用方法在NUnit中編寫一些測試,但沒有成功。 我希望我能弄清楚我的處境,因為我不得不大量解釋我的代碼。

DoBusinessLogic()是我要測試的方法。 它從基類中調用其他兩個方法:

public class MySvc : BaseSvc, IMySvc
{
    private readonly IMyRepo _repo;
    private readonly IMyConnectorClass _connector
    public MySvc(IMyRepo repo) : base(repo)        
    {
        _repo = repo;
        _connector = _repo.GetConnector();
    }

    public async Task DoBusinessLogic(int id1, int id2){
        bool doesFirstObjectExist = await CheckMainObjExists<Foo>(id1, _connector);
        await CheckSubObjExists<Bar>(id2, _connector);
        // further business logic
    }
}

這些方法依次調用相同的存儲庫方法,但其邏輯不同:

public abstract class BaseSvc : IBaseSvc
{
    private readonly IBaseRepo _repo
    protected BaseSvc(IBaseRepo repo)
    {
        _repo = repo;
    }

    protected async Task<bool> CheckMainObjExists<T>(int? id, IMyConnectorClass connector)
    {
        return await _repo.GetObjectByIdAsync<T>(Id, connector) != null;
    }

    protected async Task CheckSubObjExists<T>(int? id, IMyConnectorClass connector)
    {
        if (await _repo.GetObjectByIdAsync<T>(Id, connector) == null)
            { throw new Exception("Object not found!"); }
    }
}

接下來,我想在MySvc類中為DoBusinessLogic()編寫單元測試。 不幸的是,看來我無法模擬來自存儲庫的響應。

[TestFixture]
public class MySvcTests
{
    private MySvc _svc;
    private Mock<IMyRepo> _repoMock;
    private Mock<IMyConnectorClass> _connectorMock;

    [SetUp]
    public void SetUp()
    {
        _repoMock = new Mock<IMyRepo>() {};
        _connectorMock = new Mock<IMyConnectorClass>();

        _repo.SetUp(r => r.GetConnector()).Return(_connectorMock.Object);

        _svc = new MySvc(_repoMock);    
    }

    /* 
    My intent in this test, is to make CheckMainObjExists() pass,
    but make CheckSubObjExist() fail.
    */
    [Test]
    public async Task DoBusinessLogic_If2ndObjectNotExist_ThrowException()
    {
        // This should return an object
        _repoMock.Setup(r => r.GetObjectByIdAsync<Foo>(It.IsAny<int>(), _connectorMock.Object))
            .ReturnsAsync(new Foo());

        // This should return null
        _repoMock.Setup(r => r.GetObjectByIdAsync<Bar>(It.IsAny<int>(), _connectorMock.Object))
            .ReturnsAsync((Bar) null);

        Assert.Throws<Exception>(await _svc.DoBusinessLogic());
    }
}

但是,當我運行測試時,為我的模擬回購設置的兩個方法都返回null,而我希望第一個方法為“ true”。 我不知道問題出在哪里,但我懷疑:

  1. 是否可以使用模擬對象作為參數來設置方法? 在這種情況下,可以使用_connectorMock.Object作為設置參數嗎?
  2. 是否可以多次設置相同的泛型方法,但是每次都設置不同的類型? 首先是為Foo設置,然后是為Bar設置。

我剛剛測試了這段代碼,它可以按預期運行。 現在,我不得不做很多假設,只是為了使代碼能夠編譯和運行,這意味着我對您的代碼的測試存在缺陷,因為我可能已經修復了示例中省略的內容。

我沒有對您的測試設置代碼進行任何更改,但仍然有效。

[TestClass]
public class MySvcTests {
    [TestMethod]
    [ExpectedException(typeof(Exception))]
    public async Task DoBusinessLogic_If2ndObjectNotExist_ThrowException() {
        var _repoMock = new Mock<IMyRepo>() { };
        var _connectorMock = new Mock<IMyConnectorClass>();

        _repoMock.Setup(r => r.GetConnector()).Returns(_connectorMock.Object);

        var _svc = new MySvc(_repoMock.Object);
        // This should return an object
        _repoMock.Setup(r => r.GetObjectByIdAsync<Foo>(It.IsAny<int>(), _connectorMock.Object))
            .ReturnsAsync(new Foo());

        // This should return null
        _repoMock.Setup(r => r.GetObjectByIdAsync<Bar>(It.IsAny<int>(), _connectorMock.Object))
            .ReturnsAsync((Bar)null);

        await _svc.DoBusinessLogic(0, 0);
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM