-
Notifications
You must be signed in to change notification settings - Fork 265
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ability to mock requests from Protected methods in sequences #800
Comments
Related #222 (with a working extension method? ) |
I have created an extension method to allow me to mock up protected virtual method for this exact same thing to test methods that involve rest api calls. It would be great if we could incorporate this into NSubstitute and not have to pull down yet another nuget pkg just to get the extension method |
Hi @Jason31569 , Would you be able to send a PR with this? Maybe add to |
Sure, but I am stump trying to make this generic enough that it can be used in all (or most) use cases For example: When: It seems for all ref types NSubstitute sets the arg to null, e.g. Is there a clean way I can detect the correct type (in this case |
@Jason31569 I think you should just be able to call I'm not sure there is much point in making the return type (If I've missed the point of the question here please let me know!) |
The problem is the extension method cannot figure out the Given this class with 3 overloads:
I am doing this to find the right method (maybe there is a better way?): Unit test with var sub = Substitute.For<AnotherClass>(): Not to distract from the original issue I ran into, but I also found out that This works fine (with exact values): re the return type |
For working out arg matcher types it is probably necessary to check queued argument matchers (some discussion in this thread. Alternatively maybe it is possible to use |
@dtchepak let me know your thoughts on the changes? Didn't go the route of |
I fall into a category of people that has transitioned to using NSubstitute after discovering security concerns in Moq, which are detailed thoroughly in this article: https://medium.com/@michalsitek/critical-security-vulnerability-in-moq-4-20-0-ffd24739cc49.
So far, there has been only 1 feature of NSubstitute that was present in Moq, that is no longer possible: Mocking protected methods easily. Our company often writes unit tests for classes that make outbound http requests. In these classes that make the requests, we typically access the
System.Net.Http.HttpClient
via constructor injection. Mocking Http Requests is not exactly trivial with any mocking library, and usually involves some form of mocking the actualHttpMessageHandler
, and building a new client with the mocked handler.In Moq, you could skip all of this and simply mock the response of the protected method
SendAsync
in the unit test setup, by passing in a string value of the name of the protected method, as well as the request parameters to the method the mocked response is expecting. (Mocking the actual REST methods on the HttpClient doesn't actually work, because they all eventually call "SendAsync", which is the protected method we need to override). Here is an example of how simple it was to mock an Http request (regardless if it was Post, Put, Delete, or Get) looked like using Moq, because of the feature described:This was great because it offered a way to get granular with exactly what each Request message looked like, (by identifying requests from their outbound target address), and provide specific responses for each request. You could call "SetupSequence," and string together all of your specific requests and each specific response.
Because NSubsitute doesn't have a way to override protected methods like this, we are forced to mock the HttpClientFactory
CreateClient()
method. To do this, we have aFakeHttpMessageHandler
class that is used on top of theDelegatingHandler
to override the protected method "SendAsync." While technically this is a workaround, and does work for a single outbound http request, it only works for 1 outbound http request. We can't mock multiple requests/responses to the SendAsync method. This matters because on methods where we have 3 and 4 outbound requests with specific logic that changes the cyclical complexity and logic routing, we lose the ability to write a whole suite of thorough test cases. We also can't specify WHICH specific incoming request should have WHICH specific response. We just know that eventuallySendAsync
will be called, and when it is, toss it this response.You can see our
FakeHttpMessageHanlder
workaround below, and you will understand what I mean. We have attempted to come up with ways to inject multiple response, and sequencing, but have been unsuccessful at doing so. Additionally, we are having to include this workaround in every project we write tests for. We have over 130 repositories with LOTS of testing projects within. It is becoming cumbersome to maintain a workaround in tons of places. Please introduce this feature. It would save a lot of headache from your users. I know we are not alone, as the web is riddled with workarounds to this same problem. I have personally not seen a single implementation of a workaround that allows for getting granular on mocking sequences of requests/responses.The
FakeHttpMessageHandler
that overrides theSendAsync
method on the originalDelegatingHandler
:An example of how we use the
FakeHttpMessageHandler
, referenced in each of our tests that needs to mock a response to an outbound HttpRequest.Hopefully you are able to see the downsides in test cases without the ability to do what Moq provided. Hopefully the verbiage on this post made sense, but I am happy to clarify.
The text was updated successfully, but these errors were encountered: