簡體   English   中英

表達式<Func <T,bool >>的Moq'ing方法作為參數傳入

[英]Moq'ing methods where Expression<Func<T, bool>> are passed in as parameters

我對單元測試和嘲笑很新! 我正在嘗試編寫一些單元測試,其中包含一些與數據存儲交互的代碼。 數據訪問由IRepository封裝:

interface IRepository<T> {
    ....
    IEnumerable<T> FindBy(Expression<Func<T, bool>> predicate);
    ....
}

我正在嘗試使用具體的IoC實現的IRepository來測試的代碼如下所示:

public class SignupLogic {
    private Repository<Company> repo = new Repository<Company>();

    public void AddNewCompany(Company toAdd) {
        Company existingCompany = this.repo.FindBy(c => c.Name == toAdd.Name).FirstOrDefault();

        if(existingCompany != null) {
            throw new ArgumentException("Company already exists");
        }

        repo.Add(Company);
        repo.Save();
    }
}

因此,我正在測試SignupLogic.AddNewCompany()本身的邏輯,而不是邏輯和具體的存儲庫,我正在模擬IRepository並將其傳遞給SignupLogic。 模擬的存儲庫看起來像這樣:

Mock<Repository> repoMock = new Mock<Repository>();
repoMock.Setup(moq => moq.FindBy(c => c.Name == "Company Inc")....

它返回一個內存中的IEnumberable,其中包含名稱設置為“Company Inc”的Company對象。 調用SignupLogic.AddNewCompany的單元測試會設置一個具有重復詳細信息和trys的公司來傳遞它,並且我斷言拋出了ArgumentException,並顯示消息“公司已存在”。 這個測試沒有通過。

在運行時通過單元測試和AddNewCompany()進行調試,似乎existingCompany始終為null。 無奈之下,我發現如果我更新SignupLogic.AddNewCompany()以便對FindBy的調用如下所示:

Company existingCompany = this.repo.FindBy(c => c.Name == "Company Inc").FirstOrDefault();

測試通過,這告訴我,Moq只響應與我在測試夾具中設置的代碼完全相同的代碼。 顯然,在測試任何重復的公司被SignupLogic.AddNewCompany拒絕時,這並不是特別有用。

我已經嘗試設置moq.FindBy(...)來使用“Is.ItAny”,但這並不會導致測試通過。

從我正在閱讀的所有內容來看,似乎我正在嘗試測試表達式實際上並不能在這里使用Moq。 可能嗎? 請幫忙!

只有具有完全相同結構(和文字值)的Expression匹配才可能是正確的。 我建議您使用Returns()的重載,它允許您使用調用mock的參數:

repoMock.Setup(moq => moq.FindBy(It.IsAny<Expression<Func<Company, bool>>>())
        .Returns((Expression<Func<Company, bool>> predicate) => ...);

... ,您可以使用predicate來返回匹配的公司(如果匹配的公司不符合您的預期,甚至可能會拋出異常)。 不是很漂亮,但我認為它會起作用。

您應該能夠使用It.IsAny<>()來完成您要執行的操作。 通過使用It.IsAny<>()您只需調整設置的返回類型即可測試代碼的每個分支。

It.IsAny<Expression<Func<Company, bool>>>()

第一次測試,返回公司而不管謂詞會導致異常拋出:

var repoMock = new Mock<IRepository<Company>>();
repoMock.Setup(moq => moq.FindBy(It.IsAny<Expression<Func<Company, bool>>>())).Returns(new List<Company>{new Company{Name = "Company Inc"}});
var signupLogic = new SignupLogic(repoMock.Object);
signupLogic.AddNewCompany(new Company {Name = "Company Inc"});
//Assert the exception was thrown.

第二次測試,使返回類型為空列表將導致添加被調用:

var repoMock = new Mock<IRepository<Company>>();
repoMock.Setup(moq => moq.FindBy(It.IsAny<Expression<Func<Company, bool>>>())).Returns(new List<Company>());
var signupLogic = new SignupLogic(repoMock.Object);
signupLogic.AddNewCompany(new Company {Name = "Company Inc"});
repoMock.Verify(r => r.Add(It.IsAny<Company>()), Times.Once());

您通常只會模擬您擁有的類型。 那些你不擁有的人,真的不應該因各種困難而被嘲笑。 所以嘲弄表達 - 正如你的問題所暗示的那樣 - 不是要走的路。

在Moq框架中。 .Returns()放在函數中是很重要的,否則就不匹配了。 所以,如果你還沒有這樣做,那就是你的問題。

repoMock.Setup(moq => moq.FindBy(c => c.Name == "Company Inc").Returns(....

暫無
暫無

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

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