【问题标题】:How to fake an action<> with FakeItEasy如何使用 FakeItEasy 伪造一个动作<>
【发布时间】:2020-01-13 21:23:42
【问题描述】:

我正在使用 FakeItEasy 库为我的单元测试创​​建假货。

我有一个ClassUnderTest,我想在上面测试方法MethodToTest(Data dataObject)。此方法正在调用我要伪造的接口的方法:

public interface IFoo
{
  void Execute(Action<IDataAccess> action);
}

public class ClassUnderTest
{
  private IFoo _foo;

  public ClassUnderTest(IFoo foo)
  {
    _foo = foo;
  }

  public void MethodToTest(Data dataObject)
  {
    _foo.Execute(dataAccess => dataAccess.Update(dataObject));
  }
}

public interface IDataAccess
{
  void Update(Data data);
}

public class Data
{
  public int Property { get; set; }
}

在我的单元测试中,我想检查测试方法是否正确调用接口(使用正确的属性值):

[TestClass]
public class UnitTest1
{
  [TestMethod]
  public void TestMethod1()
  {
    var foo = A.Fake<IFoo>(x => x.Strict());
    A.CallTo(() => foo.Execute(dataAccess => dataAccess.Update(A<Data>.That.Matches(d => d.Property == 20))));      

    var cut = new ClassUnderTest(foo);

    cut.MethodToTest(new Data { Property = 20 });      
  }
}

但是在这个测试中配置有问题。我得到了例外:

测试方法TestProject1.UnitTest1.TestMethod1抛出异常: FakeItEasy.ExpectationException:调用严格伪造的未配置方法“Execute”。

有人知道我必须如何正确配置CallTo() 语句吗?

【问题讨论】:

  • 很容易,我会说...? :) (好的,好的,我会读一读...)
  • 您确定您提供的代码甚至可以编译吗? ClassUnderTest 没有无参数构造函数(我假设它是一个类 - 但代码中也缺少它),但您似乎使用了一个......
  • @decPL:你说得对,我更正了上面的示例。 foo-fake 在 costructor 中传递。
  • dataAccess 是...?
  • 我认为@decPL 正在做某事——这就是我检查Execute 是否被调用的方式,但我也认为除了所有编译错误(持续存在)之外还有其他事情发生- ClassUnderTest 没有“类”,如果没有别的)。 FakeItEasy 抱怨 foo 是一个“严格的假货”,这不是默认值。是否有您未显示的其他代码?或者可能是某个地方的IFakeConfigurator

标签: c# unit-testing mocking action fakeiteasy


【解决方案1】:

更新后的示例确实很有帮助,@rhe1980。

首先是关于您提供的测试的一些注释:

  1. A.CallTo 方法没有做任何事情 - 它没有设置行为(使用 .Invokes.Returns 甚至 .DoesNothing)或验证该方法已被调用(例如使用 @ 987654326@)。
  2. 比较Actions 似乎很难。我确实在 Compare Delegates Action<T> 找到了一些建议,但如果是我,我会采取稍微不同的策略。

与其尝试将Action 委托与参考模型进行比较,我想我可以通过捕获提供给Execute 的操作然后在IDataAccess 上运行它并查看操作来模拟这一点确实。幸运的是,我们有 FakeItEasy 提供帮助!

我通过这个测试成功了:

[TestMethod]
public void TestMethod1()
{
    // Arrange
    var foo = A.Fake<IFoo>(x => x.Strict());

    var fakeDataAccess = A.Fake<IDataAccess>();

    A.CallTo(() => foo.Execute(A<Action<IDataAccess>>.Ignored))
                    .Invokes((Action<IDataAccess> action)=>action(fakeDataAccess));

    var cut = new ClassUnderTest(foo);

    // Act
    cut.MethodToTest(new Data { Property = 20 });

    // Assert
    A.CallTo(() => fakeDataAccess.Update(A<Data>.That.Matches(d => d.Property == 20)))
        .MustHaveHappened();
}

希望对你有帮助。

【讨论】:

  • 太棒了!正是我需要的。谢谢!
【解决方案2】:

如果我正确理解您的意图,您需要使用以下内容:

A.CallTo(() => foo.Execute(A<Action<IDataAccess>>.Ignored).MustHaveHappened();

【讨论】:

  • 我同意,最好是在运行 MethodToTest 之后。不过,我认为示例代码还有其他问题。请参阅我对这个问题的评论。
猜你喜欢
  • 2012-06-02
  • 1970-01-01
  • 1970-01-01
  • 2012-07-16
  • 2022-10-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多