0

The function that I want to test:

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

The template is a class containing textrexources. TheKeyAsString is a string that is the Key for getting the correct text.

How can I unit test this?

Here is what I did hope would work. It does not work:

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");

Can anyone tell my how to set up FakeItEasy to deliver "TheText" when I call the ResourceManager like this:

string theText = _resourceManager.GetString<MyApp.Localization.MyTexts>(
                 x => x.TheKeyAsString);
Magnus
  • 45,362
  • 8
  • 80
  • 118
  • I’m unsure what the mock is here… do you actually want to test the `GetString` method of the resource manager implementation? Or do you want to *mock* that (to test something else)? – poke Dec 12 '17 at 09:25

2 Answers2

2

From your explanation, I’m unsure what you actually want to test here. Usually, you wouldn’t test the mocked/faked object since you just configured it to behave as you want to. So if _resourceManager is the fake, then a proper test would be one where you test a different component, that consumed _resourceManager and called its GetString method.

For that, a test could look like this:

// 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);

Since this happens in a very specific test scenario, you very likely don’t need to care what kind of expression was passed to the GetString method. You would only need to do that, if you expected multiple calls to the method with different expressions.

In that case though, you need to be aware that you cannot compare two expressions using ==. So your setup fails because you compare the previously created myExpression with a later one.


If you want to also test that your ComponentYouWantToTest also calls the method with the correct expression, for example to check that it uses the correct property in the lambda expression, then you could do it like this:

// 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);

If the component used a different key function other than x => x.EmailBody, it now wouldn’t get the emailBody value from the myTexts instance.

poke
  • 369,085
  • 72
  • 557
  • 602
  • Than you for your answer. What I want to test is my email class. I want to ensure that the email-class gets the correct resourcetext. Me email-class use this line of code to receive the text: _resourceManager.GetString(x => x.EmailBody); – Kjetil Salomonsen Dec 12 '17 at 11:53
  • @KjetilSalomonsen I added something to my answer to explain how you could check that the component uses the correct expression there. – poke Dec 12 '17 at 12:33
  • 1
    @KjetilSalomonsen You’re welcome! Please remember to [accept the answer](https://meta.stackexchange.com/a/5235/141542) to mark your question as resolved. – poke Dec 13 '17 at 17:30
0

The problem here is that Expression<TDelegate> doesn't implement equality. If you do this:

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

expr1 and expr2 will not be considered equal, even though they're identical.

So configuring the fake like this:

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

(equivalent to the configuration you wrote, but simpler)

will not match the actual call to _resourceManager.GetString<MyApp.Localization.MyTexts>(x => x.TheKeyAsString), because a different instance of the expression will be passed.

To solve this, you would need a way to test expressions for equality. You could compare the text representations of the expressions, like this:

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

Identical expressions will have the same text representations, but it's conceivable that different expressions could also have the same text representation, so it's not fool-proof...

Thomas Levesque
  • 286,951
  • 70
  • 623
  • 758