首页 > 解决方案 > 从使用 func 作为参数的 moq 调用扩展方法时引发异常

问题描述

我在为调用静态函数且其参数之一是 func 的方法创建单元测试时遇到问题。即使我创建了一个包装类来调用静态函数即扩展,问题仍然存在,如本文所建议的:

如何使用 Moq 模拟扩展方法?

正如有人建议的那样,我应该创建一个接口和一个包装类,但是当它达到最小起订量设置时,我仍然遇到异常。我的设置如下所示:

context.Setup(c => new MyExtensionWapper()
   .UpdateCollection<TestObject, int>(
   context.Object,
   databaseCollection,
   detachedCollection,
   o=>o.Id.Value));

错误发生在o=>o.Id.ValueMyExtensionWapper 类是 Wrapper 函数,它使用 UpdateCollection 合约实现 IExtensions。

请注意,我的 UpdateCollection 是一个通用函数,与Entity Frameworkwhere TEntityis an EF entity object & 和TKey趋向于Int.

public class MyExtensionWapper : IExtensions
{
    public virtual void UpdateCollection<TEntity, TKey>(IDbContext context, 
        ICollection<TEntity> databaseCollection, 
        ICollection<TEntity> detachedCollection, 
        Func<TEntity, TKey> keySelector)
        where TEntity : class
        where TKey : IEquatable<TKey>
    {
        context.UpdateCollection(databaseCollection, 
        detachedCollection, keySelector);
    }
}

当它达到 moqcontext.Setup(...时,我收到以下错误:

System.NotSupportedException: 'Unsupported expression: o => o.Id.Value'

你能帮我吗?

谢谢。

更新-1

这是我最初的调用,我尝试直接从模拟设置中调用静态方法(扩展):

context.Setup(c => c.UpdateCollection<TestObject, int>(
databaseCollection,
detachedCollection,
o=>o.Id.Value));

我的模拟创建如下:

context = CreateMock<IDbContext>(MockBehavior.Loose);

但是当被调用时,我收到以下错误:

System.NotSupportedException: 'Invalid setup on an extension method:....

更新 2

正如@Johnny 所建议的,我应该模拟界面,所以我尝试了以下但我得到了同样的错误:

Mock<IExtensions> dbExtension;

// Note: Results are the same whether I create the mock with a loose
// behaviour or not.
dbExtension = CreateMock<IExtensions>(MockBehavior.Loose);

dbExtension.Setup(c => new MyExtensionWapper()
    .UpdateCollection<TestObject, int>(
    context.Object,
    databaseCollection,
    detachedCollection,
    o=>o.Id.Value,

另外,我没有调用包装类,而是尝试直接从模拟中调用 UpdateCollection 方法,因为它是在接口中定义的,即 c=>c.UpdateCollection(databaseCollection, ...) 但无济于事。

标签: unit-testingmockingmoqextension-methods

解决方案


我最终使用@Johnny 建议的方法让它工作,该方法是模拟接口,但我必须对我的模拟做一些细微的改变:

dbExtension.Setup(c => c.UpdateCollection<TestObject, int>(
    context.Object,
    databaseCollection,
    detachedCollection,
    It.IsAny<Func<TestObject, int>>());

而不是通过

o=>o.Id.Value

我不通过

It.IsAny<Func<TestObject, int>>()

请注意,尝试传递It.IsAny<Func<TestObject, int>>()调用包装类的原始代码不起作用并引发以下异常:

System.InvalidOperationException: 'No coercion operator is defined 
between types 'Extensions.MyExtensionWapper' and 'Moq.Mock'.'

推荐阅读