使用RhinoMocks模拟table进行非单元测试

本文关键字:单元测试 table RhinoMocks 模拟 使用 | 更新日期: 2023-09-27 18:06:57

我有一个接口,我运行一个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()
    };

查询运行正常。在编写单元测试时,我陷入了困境。如何获得函数GetMyTable()返回一个模拟对象与一些假数据,围绕这里的待办事项:

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;
        }
 }

使用RhinoMocks模拟table进行非单元测试

如果我正确理解您的问题,您可能想要生成IMyDataContext的模拟,而不是仅为测试做自己的实现。

在IMyDataContext模拟中,您可以像这样设置期望:

var dataContext = MockRepository.GenerateMock<IMyDataContext>();
var table = MockRepository.GenerateMock<ITable<MyTable>>();
dataContext.Expect(x => x.GetMyTable()).Return(table);

您也可以在表模拟上设置期望。或者,您也可以创建一个实现ITable接口的类的新实例,并用内存中的测试数据填充该实例。

我不知道linq-to-sql,我不知道ITable。但是当我看到这个界面时,我真的怀疑你是否应该嘲笑它。这太复杂了。模拟它可能会导致编写整个数据库模拟器,这显然没有意义。单元测试应该尽可能的简单。

我建议使用实现ITable的真实类。明确一点:不要编写自己的实现。

ITable包含3个不同的接口:IEnumerable, IQueryableITable中的其他东西。由于您所做的只是查询表,因此您可以使用IQueryable并将其传递给mock/存根:

 IQueryable<MyTable> testTable = new[]{new MyTable{…}, new MyTable{…}, …, new MyTable{…}}.AsQueryable();
 myMock.Stub(x => x.GetMyTable()).Return(testTable);

每个new MyTable{…}代表表中的一行。

如果/一旦你需要完整的ITable接口,例如,因为你想从表中添加或删除行,你将想要创建自己的抽象类TestableTable,你可以扩展List(这样它已经实现了IEnumerable)并提供所有IQueryable方法:

 public SomeType SomeMethodFromIQueryable(…)
 {
      return this.AsQueryable().SomeMthodFromIQueryable(…);
 }

现在只剩下ITable中的其他东西了。这些都很容易转化为List -方法,除了.Commit(),你可以保留抽象,然后可以存根它和.AssertWasCalled(…)它。

 var myMock = MockRepository.GenerateStub<TestableTable<MyTable>>(){ new MyTable{…}, …};
 …
 myMock.AssertWasCalled(x => x.Commit());

希望对你有帮助。

注:我是在为同样的问题寻找标准解决方案时遇到你的问题的。没有找到任何东西,所以我实现了这个

这是使用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;
    }