Hey Dojo-community,
I was working on some unit tests and was wondering what the prefered method for solving the following issue is:
imagine I have three extension methods:
public static bool ContainsElementSubscriptions(this SubscriptionSetInfoMessage message)
public static bool ContainsServiceSubscriptions(this SubscriptionSetInfoMessage message)
public static bool ContainsServiceAndElementSubscriptions(this SubscriptionSetInfoMessage message)
The last extension method uses the first two to return a result.
I would like to cover each of these methods in a test, but I don't want them to be dependant on each other, to make it clear which method exactly fails.
To do this, I did the following:
Mock<SubscriptionSetInfoMessage> mockedMessage = new Mock<SubscriptionSetInfoMessage>();
mockedMessage.CallBase = true;
mockedMessage.Setup(x => x.ContainsElementSubscriptions()).Returns(true);
mockedMessage.Setup(x => x.ContainsServiceSubscriptions()).Returns(true);
When writing the unit test for the last method, I got this error when trying to mock the first two methods:
Tests.QActionTests.ContainsServiceAndElementSubscriptionsTest threw exception:
System.NotSupportedException: Unsupported expression: x => x.ContainsElementSubscriptions()
Extension methods (here: QAction.ContainsElementSubscriptions) may not be used in setup / verification expressions.
How would you solve this?
Hi Maxim
Moq is a constrained framework, customizing the implementation of an extension method is not possible.
Like Jens suggests, to do what you are after, you'd need to use an unconstrained framework such as Moles, Pose or Microsoft Fakes (the latter is part of the Enterprise edition of Visual Studio). These allow customizing the implementation of methods that cannot be done using a constrained framework (using what is typically referred to as shims).
Now, while you could use an unconstrained framework to solve this, I'm not sure you should. The current test seems to be tightly coupled with implementation details: The fact that the method under test calls the other other extension methods is not relevant from an end user perspective. The test should test the observable behavior without considering the steps taken to arrive at the result (in this case, not consider the fact that the method under test calls the other extension methods). This also allows resistance to refactoring, one of the pillars of a good unit test.
Thank you for the explanation!