-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
How to mock NLog for unit test? #923
Comments
I don't think it's possible, at least, not without some tricks. But why do you need this? You can stop all the loggers in your config (for the unit tests) - so the unit tests won't do any logging. |
Has you question being answered? |
I was hoping for some sort of solution/example. But if the answer is, "it is not possible", then I guess my question is answered. Maybe developer of NLog can consider implementing it in the future. At this time, I am passing ILogger as a parameter to all my classes that user NLog. This way I can Mock ILogger and pass my mock object instead. Then I can check if Logger methods were called as intended. |
Well, the answer is depends: The key question, what are your trying to unit test? It's not clear to me.
|
Hi, I am testing my code, not nLog of course. So #3 above is what I need to test. Can you let me know how to remove/change the configuration of NLog in the Unit Test? This will work for me when I simply want to ignore writing anything to log. But, I am trying to test if method of NLog wes called. To do this, I have to pass NLog as a parameter to my class. This way I can mock it in my unit test. Example is bellow. The reason I brought up this question, is because lots of my classes use NLog. So I have to do add NLog as parameter in contractor for each of those classes. This works just fine and it is a pliable solution. However, I am working with MVVMLight at the same time. They have a class called Messenger. This is somewhat similar to NLog, you get default messenger object through static property of the Messenger class. They have a method called OverrideDefault. You can call it like so: Messenger.OverrideDefault(mockMessenger); Now instead of me massing IMessenger object to constructor of each class that uses Messenger, I can just do the overwrite in my unit test and I know that now my mockMessenger will be returned by the Messenger static method. I found it convenient way for unit testing. So if you are one of the NLog developer or anyone from NLog team is seeing this, this is just a suggestion that you might consider for the future. [Test]
|
If you don't like the side effect of NLog, just clear the configuration: //clear configuration
LogManager.Configuration = new NLog.Config.LoggingConfiguration(); If you like to test your calls to NLog (your case) //init with empty configuration. Add one target and one rule
var configuration = new NLog.Config.LoggingConfiguration();
var memoryTarget = new MemoryTarget {Name = "mem"};
configuration.AddTarget(memoryTarget);
configuration.LoggingRules.Add(new LoggingRule("*", LogLevel.Trace, memoryTarget));
LogManager.Configuration = configuration;
var logger = LogManager.GetLogger("test");
logger.Info("ow noos");
//read the logs here
var logs = memoryTarget.Logs; Result: |
Has your question being answered? |
Closing this due to inactivity. If you still experiencing problems, just let us know. |
This is an unsatisfactory answer. Mocking NLog shouldn't be as much of a pain as that. @304NotModified: There is clearly a legit reason to want to return a pre-made ILogger in response to a GetCurrentClassLogger() call with a given type. Say I want to test that my class is correctly logging exceptions, how would you suggest I do it? I know you want people to use some in-memory full logging NLog, but really I just want GetCurrentClassLogger() to return my mock. Another alternative is to wrap LogManager in a LogManagerManager that behaves the way it should and rig that up to be testable. |
Agree, it should be easy.
Well changing the config is also kind of mocking. (change it to memorytarget, no code changes needed when logging) You could then test your write-to-NLog logic. Or do you like to test your nlog.config? That sounds a bit odd to me. |
No, unit tests should not have specific configurations. Those changes would come into all of your tests, which is not desirable. Separation of concerns and all that. To keep those config changes from effecting the rest of your test code, you would either need to have a separate config and change configs to use that other config somehow for those specific tests, or else have a completely separate test project for your logging tests. No, I do not want to test my log.config. I don't want to be within 20 miles of my log.config in test code. I just want LogManager.GetCurrentClassLogger() or similar to return me a Mock<ILogger> when I ask for a logger in my unit tests. How would you even check that something has been logged with an in-memory log anyway? I didn't know you could read through old ILogger messages. |
What's the goal you are trying to achieve with the unit tests? (Preferable in a few sentences). |
With mocking you will replace behavior by configuration. This is possible with the NLog config as you could replace targets with your own targets. (or memory target by reading it So NLog fully supports mocking |
No, I'm sorry, it doesn't. Okay, I'll keep this simple, I want to test that on an exception, a suitable exception message is logged, or even that any error message is logged at all. _mockLogger.Verify(l => l.Error(It.IsAny<string>()), Times.Once); This is doable by wrapping your LogManager in another more friendly manager class, but isn't supported out of the box. |
yes, you can do that with the memorytarget. |
If I may interject: I was also wondering whether I could verify that a system-under-test attempts to log an action and uses an appropriate log level for that. As you said, @304NotModified, that is doable with a memorytarget, but the setup needed for that is fairly lengthy and would complicate test setup. In any case, I would rather do behaviour verification instead of state verification here. I could get a Facade going, but the case for supporting it out of the box seems reasonable to me. |
I know its closed and all, but maybe the following could help someone finding this in the future. Facade for encapsulating the memoylogger:
Usage:
|
Hi,
I use NLog in most of my classes. All classes have log property:
then I use this property to write info to log.
If I want to write a unit test for a class that uses NLog, how do I substitute default logger that LogManager returns with my fake one?
One alternative is to pass ILogger parameter to all my constructors. This way I can pass real logger from the program and my mock logger that implements ILogger interface from the unit test. But is there a better way? I want to avoid writing ILogger parameters in all my constructors since most of my classes use logger.
Just as an example, MVVM Light has a class called Messenger. They have a function
Messenger.OverrideDefault(IMessenger fakeMessenger);
If you pass fake messenger into this function, then whichever class calls Messenger.Default, you would get fakeMessenger instead of the original class.
Is there something similar with NLog?
Maybe we can do something like this?
LogManager.SetCurrentClassLogger(ILogger log)
What is the best practice for testing classes that use NLog?
Thank you in advance
The text was updated successfully, but these errors were encountered: