This is a migrated thread and some comments may be shown as answers.

Mocking behaviour for an extension method of a mocked class.

4 Answers 754 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
Rob
Top achievements
Rank 1
Rob asked on 03 Apr 2019, 04:39 PM

I have a unit test that creates a mocked instance of a class and arranges some of its properties. The test then executes some extension methods of that class.

When I run the test under visual studio 2017 (JustMock 2019.1.207.1) my tests pass. When I run the same test using the VsTest v2 build task the test fails due to an unarranged mock on the class which corresponds to a call of an extension method.

The code looks something like :

public class Person {
  public string Name { get; }
}
 
public static PersonExtensions {
  public int NameLength(this Person person) {
    return person.Name.Length;
  }
}
 
var fakePerson = Mock.Create<Person>(Behavoir.Strict);
Mock.Arrange(() => fakePerson.Name).Returns("Toto"):
 
var expected = 4;
var actual = fakePerson.NameLength(); // <--- exception here
 
// ...etc.


First strange thing is the test works in visual studio but on the build server.
Second strange thing is the exception says I have declared a strict mock on the PersonExtensions static class :

Telerik.JustMock.Core.StrictMockException: Called unarranged member 'Int32 NameLength(Person)' on strict mock of type 'PersonExtensions'<br>at Telerik.JustMock.Core.Behaviors.StrictBehavior.Process(Invocation invocation)
at Telerik.JustMock.Core.MocksRepository.DispatchInvocation(Invocation invocation)
at Telerik.JustMock.Core.ProfilerInterceptor.DispatchInvocation(Invocation invocation)
at Telerik.JustMock.Core.ProfilerInterceptor.InterceptCall(RuntimeTypeHandle typeHandle, RuntimeMethodHandle methodHandle, Object[] data)
at PersonExtensions.NameLength(Person person)...

If I could reproduce the error in visual studio it would be easier to find a way around it, I will probably do some CallOriginal arranges on the extension methods of the class.

Have you any ideas ?

Thanks,

 

Rob

4 Answers, 1 is accepted

Sort by
0
Rob
Top achievements
Rank 1
answered on 03 Apr 2019, 10:45 PM
Just an update, I found the test suite that is run on the build server includes other tests that do a :

Mock.SetupStatic(typeof(PersonExtensions), Behavoir.CallOriginal);

 

Which seems to interfere with my own test. When I add the same SetupStatic to my test I can reproduce the error in visual studio.

Am I misunderstanding something here? The CallOriginal is for all methods on the static class or just its constructor? It seems as though as the framework looks for an arrangement for the NameLength method though I've put CallOriginal in the SetupStatic.


0
Accepted
Mihail
Telerik team
answered on 04 Apr 2019, 11:59 AM
Hello Rob,

When the 
Mock.SetupStatic(typeof(PersonExtensions), Behavoir.CallOriginal);
is called, the whole type PersonExtensions is enabled for an interception. Meaning that all calls to the methods in this type will be intercepted. However, Behavior.CallOriginal argument indicates that all static methods should call its original implementation.

The extension method "NameLength" that is part of PersonExtensions is static in its declaration. However, it is an instance method when it comes to execution. This is how the extension methods work.
JustMock will handle all instance methods the same way and it will use the behavior used for creating the instance mock. In this case, this is Behavior.Strict:
var fakePerson = Mock.Create<Person>(Behavior.Strict);
Meaning that all methods that are not arranged will throw an exception.

The question here is why calling the SetupStatic from one test method will interfere with another test method?
I can think of two possible reasons this to happen:

1. One of the methods is a test initialize or a class initialize method. In this case, the initialize methods should be executed in VS and at the build machine.

2. The test method where the SetupStatic is called is marked with the DisableAutomaticRepositoryResetAttribute. This attribute will prevent the automatic execution of Mock.Reset and the PersonExtensions type will continue to be intercepted until a Mock.Reset is called. In this case, when you execute only your test in VS everything will work as expected. However, when you execute all the tests, as it is the case at the build machine, the test will fail. Of course, it matters whether the two methods are called consecutively one after the other.

If this is not the case with your scenario, please provide more detailed information for both methods.


Regards,
Mihail
Progress Telerik
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
0
Rob
Top achievements
Rank 1
answered on 11 Apr 2019, 03:03 PM

Hi,

thanks for your explaination of how the extension method becomes an instnace method. I have changed to a Behavoir.CallOriginal to get past this problem.

I don't understand why my original test with Behavoir.Strict on Person worked when it was ran in isolation, if the extension method becomes an instance method of Person. Something about the SetupStatic that interferes and changes the way the mock framework works with respect to the Person class ?

In any case, I am no longer blocked, thanks!

0
Mihail
Telerik team
answered on 15 Apr 2019, 06:54 AM
Hello Rob,

One of the options in your case is indeed to use the Behavoir.CallOriginal. This way you will need to arrange only the things you need. You could also use the Behavior.Strict but you should arrange the NameLength method to call the original code.

Regarding your question on why using SetupStatic interferes with your test, I will try to further explain it in the following lines.

When you use SetupStatic for the PersonExtensions type, all of the method calls to this type will be intercepted by JustMock and the specified behaviors will be used. In the case with the extension method, the behavior used to create an instance of the Person class, Behavior.Strict, will be used as the extension method is transferred to an instance method.

In other words, the behavior used with SetupStatic is for static methods and the behavior used with Mock.Create<Person> is for instance methods.

Regards,
Mihail
Progress Telerik
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
Tags
General Discussions
Asked by
Rob
Top achievements
Rank 1
Answers by
Rob
Top achievements
Rank 1
Mihail
Telerik team
Share this question
or