开发者

Mocking an ITable using RhinoMocks for nunit testing

开发者 https://www.devze.com 2023-03-31 14:38 出处:网络
I have an interface against which I run a linq to sql query: public interface IMyDataContext : IDisposable

I have an interface against which I run a linq to sql query:

public interface IMyDataContext : IDisposable
{
    ITable<MyTable> GetMyTable();
}

On this interface, I am running a linq query:

var results = from table1 in _MyDataContext.GetMyTable() 
    group table1 by table1.Column1 into myGro开发者_运维技巧up
    orderby myGroup.Count() descending 
    select new
    {
        Column1 = myGroup.Key,
        Count = myGroup.Count()
    };

The query is running fine. Where I am stuck is while writing unit tests. How to get the function GetMyTable() return a mocked object with some fake data, around the todo here:

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


If I understand your problem correctly, you probably want to generate a mock of IMyDataContext rather than doing your own implementation for the test only.

On the IMyDataContext mock, you can setup expectations like this:

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

You can setup expectations on the table mock as well. Alternatively you can create a new instance of a class implementing the ITable interface filling this instance with in-memory test data.


I don't know linq-to-sql and I don't know ITable. But when I look at this interface, I really doubt if you should mock it. It is much too complicated. Mocking it could end up in writing a whole database simulator, which definitively doesn't make sense. The unit tests should always be as simple as possible.

I would recommend to use a real class that implements ITable. To make it clear: don't write your own implementation.


ITable contains 3 different interfaces: IEnumerable, IQueryable and the other stuff in ITable. As all you do is query the table you could use an IQueryable instead and pass it to the mock/stub:

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

each new MyTable{…} would represent a row in the table.

If/once you need the full ITable interface e.g. because you want to add or delete rows from the table you will want to create your own abstract class TestableTable you can extend List (that way it already implements IEnumerable) and offer all the IQueryable-methods by:

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

Now only the other stuff in ITable is left. Those are easy to translate into List-Methods with exception to the .Commit() which you can leave abstract and then can stub it and .AssertWasCalled(…) it.

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

Hope that helps.

P.S.: I came across your question when I was searching for a standard solution for the same problem. Didn't find anything so I implemented this.


This is with NSubstitute but you can adapt this for 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;
    }
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号