构建用于单元测试的LINQ表达式

本文关键字:LINQ 表达式 单元测试 用于 构建 | 更新日期: 2023-09-27 18:25:08

我正在为一个类编写一些单元测试,我正在测试的方法接受一个表达式,我试图构建和表达式并将其传递给该方法,但我得到了以下错误:

System.ArgumentException:静态方法需要null实例,非静态方法需要非null实例。参数名称:方法

[TestClass]
public class WhenFilterProvided : FindSubscriptionsForCurrentUserTestBase
{
    bool filterFuncWasCalled;
    private Func<UserSubscription, bool> filterFunc => (userSubscription) =>
    {
        filterFuncWasCalled = true;
        return userSubscription.SubscriptionId == "petrol.prcies.monthly";
    };
    protected override Expression<Func<UserSubscription, bool>> Filter =>
        Expression.Lambda<Func<UserSubscription, bool>>(Expression.Call(filterFunc.Method));

    [TestMethod]
    public void CallsDetailsRepository()
    {
        UserDetailsRepositoryMock.Verify(x => x.FindAsync("userId", CancellationToken.None), Times.Once);
    }
    [TestMethod]
    public void FilterFuncGetsCalledToFilterSubscriptions()
    {
        Assert.IsTrue(filterFuncWasCalled);
    }
}

构建用于单元测试的LINQ表达式

匿名方法有时作为实例方法来实现。在您的情况下,匿名方法必须是实例方法,因为您需要访问this才能访问filterFuncWasCalled。因此,您试图调用一个实例方法,但没有传递任何实例。您可以通过传递一个带有实例的常量表达式来解决这个问题:

Expression.Call(Expression.Constant(filterFunc.Target), filterFunc.Method)

但这也不起作用,因为该方法接受一个参数,而您没有传递任何参数。让我们使用与lambda表达式相同的表达式。这是实现这一点的完整Filter属性:

Expression<Func<UserSubscription, bool>> Filter { 
    get {
        var param = Expression.Parameter(typeof(UserSubscription));
        var body = Expression.Call(Expression.Constant(filterFunc.Target), filterFunc.Method, param);
        return Expression.Lambda<Func<UserSubscription, bool>>(body, param);
    }
}