想要测试一个以lambda作为输入参数的函数。我用的是假冒的

时间:2017-12-12 09:05:58

标签: c# unit-testing lambda fakeiteasy

我想测试的功能:

 string theText = _resourceManager.GetString<MyApp.Localization
                  .MyTexts>(x => x.TheKeyAsString);

模板是一个包含textrexources的类。 TheKeyAsString是一个字符串,是获取正确文本的密钥。

我如何对此进行单元测试?

这是我所希望的工作。它不起作用:

Expression<Func<MyApp.Localization.MyTexts, string>> myExpression = x => x.TheKeyAsString;

A.CallTo(() => _resourceManager.GetString<MyApp.Localization.MyTexts>(
               A<Expression<Func<MyApp.Localization.MyTexts, string>>>
              .That.Matches(x => x == myExpression )))
              .Returns("TheText");

当我像这样调用ResourceManager时,有人能告诉我如何设置FakeItEasy来提供“TheText”:

string theText = _resourceManager.GetString<MyApp.Localization.MyTexts>(
                 x => x.TheKeyAsString);

2 个答案:

答案 0 :(得分:2)

根据你的解释,我不确定你真正想在这里测试什么。通常,您不会测试模拟/伪造对象,因为您只是将其配置为按照您的意愿运行。因此,如果_resourceManager是假的,那么正确的测试将是您测试不同的组件,消费 _resourceManager并调用其{ {1}}方法。

为此,测试可能如下所示:

GetString

由于这是在非常特定的测试场景中发生的,因此您很可能不需要关心将哪种表达式传递给// arrange var resManager = A.Fake<IResourceManager>(); A.CallTo(() => resManager.GetString<MyTexts>(A<Expression<Func<MyTexts, string>>>.Ignored)) .Returns("Foo bar"); var testedObject = new ComponentYouWantToTest(resManager); // act var result = testedObject.DoSomething(); // assert Assert.Equal("Foo bar", result.SomeProperty); A.CallTo(() => resManager.GetString<MyTexts>(A<Expression<Func<MyTexts, string>>>.Ignored)) .MustHaveHappened(Repeated.AtLeast.Once); 方法。如果您希望使用不同的表达式多次调用该方法,则只需要这样做。

但是,在这种情况下,您需要注意不能使用GetString比较两个表达式。因此,您的设置会失败,因为您将之前创建的==与之后的myExpression进行了比较。

如果你还想测试你的ComponentYouWantToTest也用正确的表达式调用方法,例如检查它是否在lambda表达式中使用了正确的属性,那么你可以这样做:

// arrange
var myTexts = new MyTexts
{
    EmailBody = "emailBody",
    TheKeyAsString = "theKeyAsString",
};
var resManager = A.Fake<IResourceManager>();
A.CallTo(() => resManager.GetString<MyTexts>(A<Expression<Func<MyTexts, string>>>.Ignored))
    .ReturnsLazily(((Expression<Func<MyTexts, string>>expr) => expr.Compile()(myTexts)));

var testedObject = new ComponentYouWantToTest(resManager);

// act
var result = testedObject.DoSomething();

// assert
Assert.Equal("emailBody", result.SomeProperty);

如果组件使用了除x => x.EmailBody以外的其他键功能,则它现在不会从emailBody实例获得myTexts值。

答案 1 :(得分:0)

这里的问题是Expression<TDelegate>没有实现相等。如果你这样做:

Expression<Func<int>> expr1 = () => 42;
Expression<Func<int>> expr2 = () => 42;

expr1expr2不会被视为相同,即使它们相同。

所以像这样配置假:

A.CallTo(() => _resourceManager.GetString<MyApp.Localization.MyTexts>(x => x.TheKeyAsString))
          .Returns("TheText");

(相当于您编写的配置,但更简单)

_resourceManager.GetString<MyApp.Localization.MyTexts>(x => x.TheKeyAsString)的实际调用不匹配,因为将传递表达式的不同实例。

要解决此问题,您需要一种方法来测试表达式是否相等。您可以比较表达式的文本表示,如下所示:

A.CallTo(() => _resourceManager.GetString<MyApp.Localization.MyTexts>(
                 A<Expression<Func<MyApp.Localization.MyTexts, string>>>
                  .That.Matches(x => x.ToString() == myExpression.ToString())))
              .Returns("TheText");

相同的表达式将具有相同的文本表示,但可以想象不同的表达式也可以具有相同的文本表示,因此它不是万无一失的......