【问题标题】:Appropriate way to mock Func<>模拟 Func<> 的适当方法
【发布时间】:2018-02-12 10:10:42
【问题描述】:

您好,我正在尝试模拟以下内容:

var result = _scope.Execute<FooService, IList<FooEntity>>(x => x.GetFooEntities(fooModel));

这就是我尝试模拟它的方式:

_mockedScope
    .Setup(x => x.Execute<FooService, IList<FooEntity>>(f => f.GetFooEntities(It.IsAny<FooModel>())))
    .Returns(new List<FooEntity>)

但是当我运行测试时它会抛出一个异常

不支持的表达式:s => s.GetFooEntities(IsAny())

有什么建议可以模拟它吗?

这是我想要起订量的示例

public class Test
{
    private readonly IScope _scope;

    public Test(IScope scope)
    {
        _scope = scope;
    }

    public void Foo()
    {
        var foo = new FooEntity();

        Result<IList<Foo>> result =
            _scope.Execute<FooService, IList<Foo>>(
                "f",
                s => s.GetFoo(foo));
    }
}

public class Foo
{
}

public class FooEntity
{
}

public class FooService
{
    public List<Foo> GetFoo(FooEntity f);
}

public interface IScope
{
    Result<TResult> Execute<T1, TResult>(string temp, Func<T1, TResult> function);
}

public class Result<T>
{
    private Result(T value, Exception exception)
    {
        Value = value;
        Error = exception;
    }

    public Exception Error { get; }

    public T Value { get; }

    public bool HasError => Error != null;

    public static Result<T> Fail(Exception exception) => new Result<T>(default(T), exception);

    public static Result<T> Success(T value) => new Result<T>(value, null);
}

【问题讨论】:

  • 如果你能提供一个minimal reproducible example 那就太好了,这样我们就可以将完整的示例复制并粘贴到控制台应用程序中。
  • 另外,也许您可​​以解释一下为什么您要按自己的方式模拟事物,而不是模拟FooService
  • 您的示例中没有s。你能告诉我xfs是什么吗?
  • @mjwills 我已经添加和示例。

标签: c# unit-testing mocking moq xunit


【解决方案1】:

当 moq 使用表达式来设置模拟时,您正在尝试模拟表达式。这对于起订量来说往往非常困难,但通过匹配的参数可以解决问题。

假设Scope.Execute 方法定义如下

public interface IScope {
    Result<TResult> Execute<T, TResult>(string temp, Func<T, TResult> function);
}

使用It.IsAny 在设置依赖于表达式参数的模拟时提供灵活性。

_mockedScope
    .Setup(x => x.Execute<FooService, IList<Foo>>(It.IsAny<string>(), It.IsAny<Func<FooService, IList<Foo>>>()))
    .Returns(Result<IList<Foo>>.Success(new List<Foo>()));

It.IsAny&lt;Func&lt;FooService, IList&lt;Foo&gt;&gt;&gt;() 将覆盖调用代码中的s =&gt; s.GetFoo(foo)

给定

public class Test {
    private readonly IScope _scope;

    public Test(IScope scope) {
        _scope = scope;
    }

    public IList<Foo> Foo() {
        var foo = new FooEntity();

        Result<IList<Foo>> result = _scope.Execute<FooService, IList<Foo>>("f", s => s.GetFoo(foo));

        var value = result.Value;

        return value;
    }
}

以下完整示例用于演示上述说明

[TestClass]
public class ExpressionMock {
    [TestMethod]
    public void TestFoo() {
        //Arrange
        var _mockedScope = new Mock<IScope>();

        _mockedScope
            .Setup(x => x.Execute<FooService, IList<Foo>>(It.IsAny<string>(), It.IsAny<Func<FooService, IList<Foo>>>()))
            .Returns(Result<IList<Foo>>.Success(new List<Foo>()));

        var subject = new Test(_mockedScope.Object);

        //Act
        var actual = subject.Foo();

        //Assert
        actual.Should().NotBeNull();
    }
}

参考Moq Quickstart 以更好地了解如何使用该框架

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-23
    • 2021-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-29
    • 2020-08-19
    • 1970-01-01
    相关资源
    最近更新 更多