Mocking EventLog and EventLogEntry
I'm trying to write unit tests for an application that reports on Entries in an EventLog. Right now when I run the unit tests, I'm having to create a temporary EventLog, write entries to it, and delete the log when I'm done. I'm doing this because I need to get back the EventLogEntry object, which have no constructor.
My question is are there any ways of mocking an EventLog to be able to get back EventLogEntries. Having to write entries to the a开发者_如何学Pythonctual EventLog seems more like integration testing than unit testing to me.
This is similar to another question I just answered today - How do I unit-test saving file to the disk?
The only difference being that - your dependencies are the EventLog and related classes. Let us assume that you just need to log some text with a severity.
struct Event
{
public string Description {get; set;}
public Severity Severity {get; set;}
}
interface Logger
{
void WriteEvent(Event e);
void IEnumerable<Event> GetEvents();
}
Now since EventLog is a .Net class which you cannot coerce to an Logger interface, you'd need an Adapter
public EventLogAdapter : Logger {
//delegates to .Net framework's EventLog
// Also EventLogEntry is internal to this class - entries will be mapped to Event structs
}
Now all we need are tests... easy as UIA or 123
- Unit tests for classes that depend on Logger will use a mock.
- Write integration tests to verify that the API for EventLogAdapter actually writes stuff and reads from the Windows EventLog
- Write at least one acceptance test that verifies an end to end scenario which causes some logging i.e. verify that an EventLogAdapter is plugged in correctly.
You would be correct that this is more of an integration test. However you need to ask yourself what you are really trying to test here. If it is truly a unit test, and you only want to test the logic over your EventLogEntries, then you should treat the event log like any other external dependency.
TDD has lead me down the road of isolating and mocking many things that feel strange to mock, but have ended up saving me from maintenance nightmares later on. i.e. File IO, Logging, Tracing, etc...
I would stick all your CRUD operations to the event log behind an interface boundary and treat it as if it were data access. If you can't easily create EventLogEntries out of band, then you might even consider creating your own entities that represent entries from the event log and use them.
This is where interfaces are really useful. Have your class rely on IEventLog instead of EventLog. Then, in your tests, you can mock out IEventLog and verify that the methods you expect to be called on IEventLog are indeed getting called.
If you want to insert a recorder into your class to capture everything (class EventLogRecorder : IEventLog
) you can do that too... and do whatever you need.
Loose coupling is where you want to be going here...
精彩评论