在NHibernate会话上模拟查询时,NSubstitute抛出CouldNotSetReturnDueToTypeMismatchException

时间:2014-09-16 05:53:05

标签: nhibernate extension-methods iqueryable nsubstitute

我有一个提供GetAll方法的存储库,它再次调用NHibernate的ISession实例上的Query扩展方法。

public ICollection<Product> GetAll()
{
    return _session.Query<Product>().ToList();
}

我的单元测试如下:

[Test]
public void GetAllReturnsCollectionFromSession()
{
    IQueryable<Product> productList = new ProductListBuilder().Build().AsQueryable();

    _fixture.Session.Query<Product>().Returns(productList);

    var sut = _fixture.CreateSut();

    var result = sut.GetAll();

    Assert.AreSame(productList, result);

    _fixture.Session.Received().Query<Product>();
}

在_fixture.Session.Query()。返回(productList)语句中,NSubstitute抛出以下异常:

NSubstitute.Exceptions.CouldNotSetReturnDueToTypeMismatchException : Can not return value of type IQueryable`1Proxy for ISession.GetSessionImplementation (expected type ISessionImplementor).

Make sure you called Returns() after calling your substitute (for example: mySub.SomeMethod().Returns(value)),
and that you are not configuring other substitutes within Returns() (for example, avoid this: mySub.SomeMethod().Returns(ConfigOtherSub())).

If you substituted for a class rather than an interface, check that the call to your substitute was on a virtual/abstract member.
Return values cannot be configured for non-virtual/non-abstract members.

Correct use:
    mySub.SomeMethod().Returns(returnValue);

Potentially problematic use:
    mySub.SomeMethod().Returns(ConfigOtherSub());
Instead try:
    var returnValue = ConfigOtherSub();
    mySub.SomeMethod().Returns(returnValue);

   at NSubstitute.Core.ConfigureCall.CheckResultIsCompatibleWithCall(IReturn valueToReturn, ICallSpecification spec)
   at NSubstitute.Core.ConfigureCall.SetResultForLastCall(IReturn valueToReturn, MatchArgs matchArgs)
   at NSubstitute.Core.CallRouter.LastCallShouldReturn(IReturn returnValue, MatchArgs matchArgs)
   at NSubstitute.Core.SubstitutionContext.LastCallShouldReturn(IReturn value, MatchArgs matchArgs)
   at NSubstitute.SubstituteExtensions.Returns[T](MatchArgs matchArgs, T returnThis, T[] returnThese)
   at NSubstitute.SubstituteExtensions.ReturnsForAnyArgs[T](T value, T returnThis, T[] returnThese)
   at Statoil.Wellcom.DataLayer.Implementation.Oracle.UnitTests.Repositories.DwapplicationRepositoryTests.GetAllReturnsCollectionFromSession() in C:\git\WELLCOM\source\Statoil.Wellcom.DataLayer.Implementation.Oracle.UnitTests\Repositories\DwapplicationRepositoryTests.cs:line 123

由于Query是一种扩展方法,看起来NSubstitute无法设置返回值。我如何在ISession上模拟扩展方法调用?

2 个答案:

答案 0 :(得分:1)

最简单的解决方案是将您的ISession包装在另一个接口/具体类中,以便将其存根:

public interface ISessionWrapper 
{
    IQueryable<T> Query<T>();
}

public class SessionWrapper : ISessionWrapper
{
    private readonly ISession _session;

    public SessionWrapper(ISession session)
    {
        _session = session;
    }

    public IQueryable<T> Query<T>()
    {
        return _session.Query<T>();
    }
}

答案 1 :(得分:0)

无法使用NSubstitute模拟扩展方法,但是如果您知道内部使用的扩展方法,那么您可以模拟它。您的测试将在模拟对象上使用扩展方法,最终它将使用模拟方法。困难的部分是知道内部发生了什么。

它在项目中对我有用,我知道所有的源代码,我可以查看里面的内容。