-
Notifications
You must be signed in to change notification settings - Fork 5.9k
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
Beware when mocking in unit tests! #30456
Comments
I'd like to learn more about how you got to the state where you added a custom interpolated string handler in a class that needed mocking. I hadn't considered the case where those would be combined. First, I expect that most .NET developers will use the interpolated string handlers provided by the .NET runtime. Second, I expected that custom handlers would only be created for performance reasons where not creating the output string, or truncating the output could save important machine cycles, I'd like to know more about what I missed in that analysis. |
First I created my own class for logging. Several other classes use this, but I wanted to abstract logging out when unit testing those other classes. So I created an interface for the logging class, and mocked it in the unit tests. Subsequently, I read about the ability to implement an interpolated string handler and decided it would be a good performance improvement for my logging class. Then reality hit - all those unit tests started to fall apart when I tried (and failed) to mock the new method that needs the interpolated string handler ref struct as an argument. I fixed the tests by using the real logging class in all the tests; I couldn't see any other way. You could argue that if the logging class is adequately tested then this is not a big deal. The big deal is that I didn't anticipate this problem and got to a place where it either took a long time to fix or else I had to abandon the interpolated string handler.
|
If you're using the |
I've written my own interface. (When I read up on what's already out there, I found it somewhat overwhelming, and yet nothing seemed to do exactly what I needed.) But in any case, my unit tests of classes that use logging needed to verify that error conditions had been communicated to the logger, so a null logger wouldn't really help with that. |
I didn't realize that this was related to this tutorial: https://docs.microsoft.com/dotnet/csharp/whats-new/tutorials/interpolated-string-handler This isn't an official runtime type, it's all custom, and this article doesn't discuss unit testing. I'm not so sure that this is really an issue at all, but I'll defer to @BillWagner. |
My point is that by not discussing unit testing, anyone doing Test Driven Development and incorporating ideas from this tutorial is in for a potentially nasty surprise, unless they are fully aware of a mocking framework's inability to mock methods with ref struct parameters. I'm guessing not many developers are aware of that. I think the article should carry at minimum a one-sentence warning about this pitfall. |
When one's logging class implements an interface, and that interface is used to make a mock for unit testing, the addition of the "public void LogMessage(LogLevel level, LogInterpolatedStringHandler builder)" method prevents a mock from being fully implemented. This is because the LogInterpolatedStringHandler is a ref struct, and mocking frameworks will not allow ref structs to be used as arguments to mocked methods. This could be a serious problem for some people. I solved it in my case by replacing all mocked instances with the real thing, which was about 2 hours' work, and left my unit tests dependent on another class, which I didn't appreciate.
Document Details
⚠ Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.
Associated WorkItem - 345701
The text was updated successfully, but these errors were encountered: