![](/img/trans.png)
[英]Moq Expression with Constraint … It.Is<Expression<Func<T, bool>>>
[英]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.