如何使用 Rhino Mocks 存根 IQueryable.Where(Func) ?

发布于 2024-07-18 05:12:20 字数 1884 浏览 9 评论 0原文

在我现在正在处理的 .net 3.5 项目中,我正在为服务类编写一些测试。

public class ServiceClass : IServiceClass
{
     private readonly IRepository _repository;

     public ServiceClass(IRepository repository)
     {
          _repository = repository;
     }

     #region IServiceClass Members

     public IEnumerable<ActionType> GetAvailableActions()
     {
         IQueryable<ActionType> actionTypeQuery = _repository.Query<ActionType>();
         return actionTypeQuery.Where(x => x.Name == "debug").AsEnumerable();
     }

     #endregion
}

我很难弄清楚如何存根或模拟该

actionTypeQuery.Where(x => x.Name == "debug")

部分。

这是我到目前为止得到的:

[TestFixture]
public class ServiceClassTester
{
    private ServiceClass _service;
    private IRepository _repository;
    private IQueryable<ActionType> _actionQuery;
    [SetUp]
    public void SetUp()
    {
        _repository = MockRepository.GenerateMock<IRepository>();
        _service = new ServiceClass(_repository);
    }

    [Test]
    public void heres_a_test()
    {
        _actionQuery = MockRepository.GenerateStub<IQueryable<ActionType>>();

        _repository.Expect(x => x.Query<ActionType>()).Return(_actionQuery);
        _actionQuery.Expect(x => x.Where(y => y.Name == "debug")).Return(_actionQuery);

        _service.GetAvailableActions();

        _repository.VerifyAllExpectations();
        _actionQuery.VerifyAllExpectations();
    }

}

[注意:类名已更改以保护无辜者]

但这会失败,并出现 System.NullReferenceException 所以

_actionQuery.Expect(x => x.Where(y => y.Name == "debug")).Return(_actionQuery);

我的问题是:

如何模拟或存根 IQueryable。在哪里使用 RhinoMocks 并让这个测试通过?

如果我当前的设置不允许我模拟或存根 IQueryable,请给出合理的解释。

感谢您阅读这个非常长的问题。

In the .net 3.5 project that I am working on right now, I was writing some tests for a service class.

public class ServiceClass : IServiceClass
{
     private readonly IRepository _repository;

     public ServiceClass(IRepository repository)
     {
          _repository = repository;
     }

     #region IServiceClass Members

     public IEnumerable<ActionType> GetAvailableActions()
     {
         IQueryable<ActionType> actionTypeQuery = _repository.Query<ActionType>();
         return actionTypeQuery.Where(x => x.Name == "debug").AsEnumerable();
     }

     #endregion
}

and I was having a hard time figuring out how to stub or mock the

actionTypeQuery.Where(x => x.Name == "debug")

part.

Here's what I got so far:

[TestFixture]
public class ServiceClassTester
{
    private ServiceClass _service;
    private IRepository _repository;
    private IQueryable<ActionType> _actionQuery;
    [SetUp]
    public void SetUp()
    {
        _repository = MockRepository.GenerateMock<IRepository>();
        _service = new ServiceClass(_repository);
    }

    [Test]
    public void heres_a_test()
    {
        _actionQuery = MockRepository.GenerateStub<IQueryable<ActionType>>();

        _repository.Expect(x => x.Query<ActionType>()).Return(_actionQuery);
        _actionQuery.Expect(x => x.Where(y => y.Name == "debug")).Return(_actionQuery);

        _service.GetAvailableActions();

        _repository.VerifyAllExpectations();
        _actionQuery.VerifyAllExpectations();
    }

}

[Note: class names have been changed to protect the innocent]

But this fails with a System.NullReferenceException at

_actionQuery.Expect(x => x.Where(y => y.Name == "debug")).Return(_actionQuery);

So my question is:

How do I mock or stub the IQueryable.Where function with RhinoMocks and get this test to pass?

If my current setup won't allow me to mock or stub IQueryable, then give a reasoned explanation why.

Thanks for reading this epically long question.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

假面具 2024-07-25 05:12:20

不使用Rhino模拟,您可以创建一个列表,然后对其调用.AsQueryable()。 例如,

var actionTypeList = new List<ActionType>() {
    new ActionType {},  //put your fake data here
    new ActionType {}
};

var actionTypeRepo = actionTypeList.AsQueryable();

这至少会给你一个假存储库,但它不会让你验证方法是否被调用。

Without using Rhino mocks, you can create a List and then call .AsQueryable() on it. e.g.

var actionTypeList = new List<ActionType>() {
    new ActionType {},  //put your fake data here
    new ActionType {}
};

var actionTypeRepo = actionTypeList.AsQueryable();

That will at least get you a fake repository, but it won't let you verify that methods were called.

浅黛梨妆こ 2024-07-25 05:12:20

其中是一个扩展方法,这不是接口IQueriable实现的方法。 查看 IQueriable 的成员: http://msdn.microsoft .com/en-us/library/system.linq.iqueryable_members.aspx

扩展方法是静态的,无法模拟。 IMO,没有必要模拟 Where,因为它是语言的一部分。 您应该只模拟存储库。

编辑,示例:

[TestFixture]
public class ServiceClassTester
{
    private ServiceClass _service;
    private IRepository _repository;
    private IQueryable<ActionType> _actionQuery;

    [SetUp]
    public void SetUp()
    {
        _service = new ServiceClass(_repository);

        // set up the actions. There is probably a more elegant way than this.
        _actionQuery = (new List<ActionType>() { ActionA, ActionB }).AsQueryable();

        // setup the repository
        _repository = MockRepository.GenerateMock<IRepository>();
        _repository.Stub(x => x.Query<ActionType>()).Return(_actionQuery);
    }

    [Test]
    public void heres_a_test()
    {
        // act
        var actions = _service.GetAvailableActions();

        // assert
        Assert.AreEqual(1, actions.Count());
        // more asserts on he result of the tested method
    }

}

注意:您不需要期待调用,因为您的方法取决于模拟的返回值。 如果它不调用它,它的断言就会失败。 这使您的测试更易于维护。

Where is an extension method, this is not a method implemented by the interface IQueriable. Look at the members of IQueriable: http://msdn.microsoft.com/en-us/library/system.linq.iqueryable_members.aspx

An extension method is static and can't be mocked. IMO, there is no need to mock Where, because it's part of the language. You should only mock the repository.

Edit, Example:

[TestFixture]
public class ServiceClassTester
{
    private ServiceClass _service;
    private IRepository _repository;
    private IQueryable<ActionType> _actionQuery;

    [SetUp]
    public void SetUp()
    {
        _service = new ServiceClass(_repository);

        // set up the actions. There is probably a more elegant way than this.
        _actionQuery = (new List<ActionType>() { ActionA, ActionB }).AsQueryable();

        // setup the repository
        _repository = MockRepository.GenerateMock<IRepository>();
        _repository.Stub(x => x.Query<ActionType>()).Return(_actionQuery);
    }

    [Test]
    public void heres_a_test()
    {
        // act
        var actions = _service.GetAvailableActions();

        // assert
        Assert.AreEqual(1, actions.Count());
        // more asserts on he result of the tested method
    }

}

Note: you don't need to expect the call, because your method depends on the return value of the mock. If it wouldn't call it, it would fail on the asserts. This makes your test easier to maintain.

帅冕 2024-07-25 05:12:20

我最初也想模拟像“IQueryable.Where(Func)”这样的调用,但我认为它在错误的级别进行测试。 相反,在我的测试中,我只是模拟了 IQueryable,然后检查结果:

// Setup a dummy list that will be filtered, queried, etc
var actionList = new List<ActionType>()
{
    new ActionType() { Name = "debug" },
    new ActionType() { Name = "other" }
};
_repository.Expect(x => x.Query<ActionType>()).Return(actionList);

var result = _service.GetAvailableActions().ToList();

// Check the logic of GetAvailableActions returns the correct subset 
// of actionList, etc:
Assert.That(result.Length, Is.EqualTo(1));
Assert.That(result[0], Is.EqualTo(actionList[0]);

_repository.VerifyAllExpectations();

I initially wanted to mock out calls like 'IQueryable.Where(Func)' too but I think it is testing at the wrong level. Instead in my tests I just mocked out IQueryable and then check the result:

// Setup a dummy list that will be filtered, queried, etc
var actionList = new List<ActionType>()
{
    new ActionType() { Name = "debug" },
    new ActionType() { Name = "other" }
};
_repository.Expect(x => x.Query<ActionType>()).Return(actionList);

var result = _service.GetAvailableActions().ToList();

// Check the logic of GetAvailableActions returns the correct subset 
// of actionList, etc:
Assert.That(result.Length, Is.EqualTo(1));
Assert.That(result[0], Is.EqualTo(actionList[0]);

_repository.VerifyAllExpectations();
烟花肆意 2024-07-25 05:12:20

我也遇到过类似的问题,我尝试将谓词表达式存根到包含字符串的 Find-method,但 String 是引用类型,当然是不可变的。 在我创建 testPredicate 并将其传递给存根、实际 SUT 并最终进行断言之前,没有成功。 下面的代码有效。

    [Test()]
    public void Search_Apartment_With_Spesific_Address()
    {
        //ARRANGE
        var repositoryMock = MockRepository.GenerateMock<IApartmentRepository>();
        var notificationMock = MockRepository.GenerateMock<INotificationService>();
        var service = new ApartmentService(repositoryMock, notificationMock);
        var apartment = new List<Apartment> {new Apartment {Address = "Elm Street 2"}}.AsQueryable();

        Expression<Func<Apartment, bool>> testPredicate = a => a.Address == "Elm Street 2";
        repositoryMock.Stub(x => x.Find(testPredicate)).Return(apartment);

        //ACT
        service.Find(testPredicate);

        //ASSERT
        repositoryMock.AssertWasCalled(x => x.Find(testPredicate));
    }

I've had similar problem where I tried to stub predicate expression to Find-method which contains string, but String is reference type and immutable of course. No success until I've create testPredicate which I pass to stub, actual SUT and finally to assert. Below code works.

    [Test()]
    public void Search_Apartment_With_Spesific_Address()
    {
        //ARRANGE
        var repositoryMock = MockRepository.GenerateMock<IApartmentRepository>();
        var notificationMock = MockRepository.GenerateMock<INotificationService>();
        var service = new ApartmentService(repositoryMock, notificationMock);
        var apartment = new List<Apartment> {new Apartment {Address = "Elm Street 2"}}.AsQueryable();

        Expression<Func<Apartment, bool>> testPredicate = a => a.Address == "Elm Street 2";
        repositoryMock.Stub(x => x.Find(testPredicate)).Return(apartment);

        //ACT
        service.Find(testPredicate);

        //ASSERT
        repositoryMock.AssertWasCalled(x => x.Find(testPredicate));
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文