[英]Mocking an ITable using RhinoMocks for nunit testing
我有一個接口,我針對它運行 linq 到 sql 查詢:
public interface IMyDataContext : IDisposable
{
ITable<MyTable> GetMyTable();
}
在這個界面上,我正在運行一個 linq 查詢:
var results = from table1 in _MyDataContext.GetMyTable()
group table1 by table1.Column1 into myGroup
orderby myGroup.Count() descending
select new
{
Column1 = myGroup.Key,
Count = myGroup.Count()
};
查詢運行良好。 我被困的地方是在編寫單元測試時。 如何獲取 function GetMyTable() 返回一個帶有一些假數據的模擬 object,圍繞這里的待辦事項:
public class MockMyContextWrapper : IMyDataContext
{
public void Dispose()
{
}
public ITable<MyTable> GetMyTable()
{
var table = MockRepository.GenerateMock<ITable<MyTable>>();
//todo: code to return something so that the linq query fired on this table works
return table;
}
}
如果我正確理解你的問題,你可能想要生成 IMyDataContext 的模擬,而不是只為測試做你自己的實現。
在 IMyDataContext 模擬中,您可以像這樣設置期望:
var dataContext = MockRepository.GenerateMock<IMyDataContext>();
var table = MockRepository.GenerateMock<ITable<MyTable>>();
dataContext.Expect(x => x.GetMyTable()).Return(table);
您也可以在模擬表上設置期望值。 或者,您可以創建一個 class 的新實例,實現 ITable 接口,用內存中的測試數據填充該實例。
ITable
包含 3 個不同的接口: IEnumerable
、 IQueryable
和ITable
中的其他內容。 正如您所做的只是查詢表,您可以使用IQueryable
代替並將其傳遞給模擬/存根:
IQueryable<MyTable> testTable = new[]{new MyTable{…}, new MyTable{…}, …, new MyTable{…}}.AsQueryable();
myMock.Stub(x => x.GetMyTable()).Return(testTable);
每個new MyTable{…}
都代表表中的一行。
如果/一旦你需要完整的ITable
接口,例如因為你想從表中添加或刪除行,你將想要創建你自己的抽象 class TestableTable 你可以擴展List
(這樣它已經實現了IEnumerable
)並提供所有IQueryable
-methods經過:
public SomeType SomeMethodFromIQueryable(…)
{
return this.AsQueryable().SomeMthodFromIQueryable(…);
}
現在只剩下ITable
中的其他內容了。 這些很容易轉化為List
-Methods,但.Commit()
,您可以保留抽象,然后可以將其存根和.AssertWasCalled(…)
。
var myMock = MockRepository.GenerateStub<TestableTable<MyTable>>(){ new MyTable{…}, …};
…
myMock.AssertWasCalled(x => x.Commit());
希望有所幫助。
PS:我在為同一問題尋找標准解決方案時遇到了你的問題。 沒有找到任何東西,所以我實現了這個。
這是與 NSubstitute 一起使用的,但您可以針對 Rhino 進行調整。
[TestMethod]
public void Your_Test_Method()
{
var jobs = new List<JobInstance> { new JobInstance { JobInstanceId = 123 } };
ITable<JobInstance> jobsTable = FakeTable(jobs);
this.wfDataContext.JobInstances.Returns(jobsTable);
...
}
/// <summary>Sets up ITable substitution</summary>
/// <typeparam name="T">Type of ITable set</typeparam>
/// <param name="data">Data to work with</param>
/// <returns>Substituted ITable set</returns>
private static ITable<T> FakeTable<T>(List<T> data)
where T : class
{
IQueryable<T> dataQueryable = data.AsQueryable();
var fakeTable = Substitute.For<ITable<T>>();
fakeTable.Provider.Returns(dataQueryable.Provider);
fakeTable.Expression.Returns(dataQueryable.Expression);
fakeTable.ElementType.Returns(dataQueryable.ElementType);
fakeTable.GetEnumerator().Returns(dataQueryable.GetEnumerator());
return fakeTable;
}
我不知道 linq-to-sql 也不知道ITable
。 但是當我看到這個界面時,我真的懷疑你是否應該嘲笑它。 這太復雜了。 Mocking 它最終可能會編寫一個完整的數據庫模擬器,這顯然沒有意義。 單元測試應始終盡可能簡單。
我建議使用實現ITable
。 明確一點:不要編寫自己的實現。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.