Unit Testing using Moq and Autofac - c#

I have the following logger logger class and I want to know the best to unit testing it.
Some observations:
I needed to create the interface IFileWrapper in order to break dependency with System.IO dependency and been able to user dependency injection (Autofac)
I was able to unit testing the method FileWrapper.WriteLog by implementing IFileWrapper using a MemoryString but if I wanted to test a expected behavior inside the method I won't be able (e.g: throwing exceptions, incorrect path and filename, etc.)
/// <summary>
/// Creates an instance of type <see cref="FileLogger"/>
/// </summary>
/// <remarks>Implements the Singleton Pattern</remarks>
private FileLogger()
{
FileName = string.Format("\\{0: MMM dd, yy}.log", DateTime.Now);
Path = Environment.CurrentDirectory;
FileWrapper = ContainerBuilderFactory.Container.Resolve<IFileWrapper>();
}
/// <summary>
/// Log the <paramref name="Message"/> in the <paramref name="Path"/> specified.
/// The <paramref name="UserName"/>, <paramref name="Host"/> must be supplied
/// </summary>
/// <example>
/// <code>
/// var handler = new LoggerHandlerFactory();
/// var logger = handler.GetHandler<FileLogger>();
/// logger.Log("Hello CSharpLogger");
/// </code>
/// </example>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="ArgumentException"></exception>
/// <exception cref="NotSupportedException"></exception>
/// <exception cref="FileNotFoundException"></exception>
/// <exception cref="IOException"></exception>
/// <exception cref="SecurityException"></exception>
/// <exception cref="DirectoryNotFoundException"></exception>
/// <exception cref="UnauthorizedAccessException"></exception>
/// <exception cref="PathTooLongException"></exception>
/// <exception cref="ArgumentOutOfRangeException"></exception>
/// <exception cref="FormatException"></exception>
public void Log(string message, LogLevel level = LogLevel.INFO)
{
lock (_current)
{
var configLevel = CSharpLoggerConfiguration.Configuration.GetLogLevel();
if (configLevel != LogLevel.OFF & level != LogLevel.OFF && configLevel >= level)
{
try
{
FileWrapper.WriteLog(string.Concat(Path, FileName), message, level);
}
catch (CSharpLoggerException)
{
throw;
}
}
}
}
So, I created the following UnitTesting using Moq:
//arrange
CSharpLoggerConfiguration.Configuration.SetLogLevel(LogLevel.DEBUG);
var mock = new Mock<IFileWrapper>();
mock.Setup(x => x.WriteLog(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<LogLevel>()));
logger.FileWrapper = mock.Object;
//act
logger.Log("Hello CSharpLogger", LogLevel.DEBUG);
logger.Log("Hello CSharpLogger", LogLevel.WARN);
//assert
mock.Verify(x => x.WriteLog(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<LogLevel>()), Times.Exactly(2));
So far so good. What I'm not confortable is with this line: logger.FileWrapper = mock.Object; I would like to keep FileWrapper propety private.
Any advise is welcome.
I'll be publishing the code http://csharplogger.codeplex.com/ in case you want more details.

Use constructor injection. In short; instead of providing the service (in this case the file wrapper) by setting a property, make the logger have a public constructor which takes an IFileWrapper argument.
public class Logger
{
public Logger(IFileWrapper fileWrapper)
{
FileWrapper = fileWrapper;
}
public IFileWrapper FileWrapper { get; }
}
// in your test:
var logger = new Logger(mock.Object);
To answer the question about having a singleton file wrapper more thoroughly, here's a code sample for the application (non-test) code:
public static class FileWrapperFactory
{
private static IFileWrapper _fileWrapper;
public static IFileWrapper GetInstance()
{
return _fileWrapper ?? (_fileWrapper = CreateInstance());
}
private static IFileWrapper CreateInstance()
{
// do all the necessary setup here
return new FileWrapper();
}
}
public class StuffDoer
{
public void DoStuff()
{
var logger = new FileLogger(FileWrapperFactory.GetInstance());
logger.WriteLog("Starting to do stuff...");
// do stuff
logger.WriteLog("Stuff was done.");
}
}
Since the FileWrapperFactory maintains a static instance of the file wrapper, you'll never have more than one. However, you can create multiple loggers like that, and they don't have to care. If you, in the future, decide that it's OK to have many file wrappers, the logger code doesn't have to change.
In a real-world application, I'd advice you to choose some kind of DI framework to handle all this book-keeping for you; most have excellent support for singleton instances, doing essentially what the FileWrapperFactory above does (but usually in a more sophisticated and robust way. FileWrapperFactory isnt' thread-safe, for example...).

Since your code comments show that your logger is a singleton, you need a way other than constructor injection for setting the dependency. In his book on Legacy Code, Mike Feathers suggests a function for such purposes, which is adequately named, something like
public void SetInstanceForTesting(IFileWrapper fileWrapper) {...}
Now this function won't hopefully be used for different purposes...

Related

Inaccessible due to protection level in C#

I have references object which contains abstract LoggerFile class. I am trying to access it. But it is showing inaccessible due to protection level. Please anyone help me to understand it.
abstract class LoggerFile
{
private static String logFile = null;
/// <summary>
/// Logfile Property
/// </summary>
public static string LogFile { get => logFile; set => logFile = value; }
/// <summary>
/// Set logFile
/// </summary>
/// <param name="logFile">The absolute path to file for writting logs</param>
public static void SetLogFile(String logFile)
{
LogFile = LogFile ?? logFile;
if (!File.Exists(LogFile))
{
File.Create(LogFile).Close();
}
}
}
}
I am calling this in another class.
using DriverAutomation.Loggin[enter image description here][1]g;
public class Devcon
{
private static Devcon devcon = null;
private readonly String devconEXE;
private readonly String devconPath;
private readonly String devconExeName;
private readonly Logger logger;
/// <summary>
/// DevconStatus Property for devcon status outcome backup
/// </summary>
public readonly String devconStatus;
/// <summary>
/// Initializes the Devcon Singleton Instance
/// </summary>
private Devcon()
{
devcon = this;
logger = Logger.GetLogger(GetType().Name, LoggerFile.LogFile);
devconExeName = "devcon.exe";
devconEXE = Path.Combine(Directory.GetCurrentDirectory(), devconExeName);
}
}
This is working within created solution. But using reference object it is showing error. Please find image.
Declare your class as public and non-Abstract and I think it will solve your problem.
public class LoggerFile
By the way, why is it even Abstract. If you only have some static members in it, maybe you should just turn it to static itself.
Though in most logger implementations, it makes sense to follow the singleton pattern (one of the few cases)

Temporary logging suppression for a scope in Serilog

I need to be able to temporarily disable logging for some scope. In my case there is a background task which periodically attempts to instantiate some device API for every available COM port in the system and sees if it fails. That API writes a lot of information to log in case of failure (exceptions, internal components Dispose calls, etc). As a result, the log is flooded with such unsuccessful attempts errors every second.
I came up with the solution that uses LogContext.PushProperty to identify the supressed log events. However, the following code won't log anything:
internal static class Program
{
public static void Main(String[] args)
{
void StartListeningSomething()
{
Task.Factory.StartNew(() =>
{
while (true)
{
Log.Information("Listening");
Thread.Sleep(500);
}
}, TaskCreationOptions.LongRunning);
}
Log.Logger = new LoggerConfiguration()
.Enrich.WithThreadId()
.Filter.ByExcluding(logEvent => logEvent.Properties.ContainsKey("SuppressLogging"))
.Enrich.FromLogContext()
.WriteTo.Console(new JsonFormatter())
.CreateLogger();
using (LogContext.PushProperty("SuppressLogging", true))
{
StartListeningSomething();
Console.ReadKey(); // Will ignore background thread log messages until key enter
}
// We want to start logging events after exiting using block
// But they won't be logged for listener thread at all
Console.ReadKey();
}
}
All log events inside listener task will be enriched with "SupressLogging" property even after popping it from the scope.
The only workaround I found (except the tedious passing customized ILogger throughout the entire API) consists of the following steps:
Assign some unique value to "SupressLogging" property
Add this value to internal static storage
When exiting scope, remove this value from storage (invalidate)
In Filter section of the logger configuration, check for property being attached and it's value being valid (contained in storage).
The following code uses custom IDisposable token to make it seem like usual PushProperty
internal static class Program
{
public static void Main(String[] args)
{
void StartListeningSomething()
{
Task.Factory.StartNew(() =>
{
while (true)
{
Log.Information("Listening");
Thread.Sleep(500);
}
}, TaskCreationOptions.LongRunning);
}
Log.Logger = new LoggerConfiguration()
.Enrich.WithThreadId()
.Filter.ByExcluding(logEvent => logEvent.IsSuppressed()) // Check if log event marked with supression property
.Enrich.FromLogContext()
.WriteTo.Console(new JsonFormatter())
.CreateLogger();
using (SerilogExtensions.SuppressLogging())
{
StartListeningSomething();
Console.ReadKey(); // Will ignore background thread log messages until some key is entered
}
// Will start logging events after exiting the using block
Console.ReadKey();
}
}
And the actual SerilogExtensions:
/// <summary>
/// Provides helper extensions to Serilog logging.
/// </summary>
public static class SerilogExtensions
{
private const String SuppressLoggingProperty = "SuppressLogging";
private static readonly HashSet<Guid> ActiveSuppressions = new HashSet<Guid>();
/// <summary>
/// Get disposable token to supress logging for context.
/// </summary>
/// <remarks>
/// Pushes "SuppressLogging" property with unique value to SerilogContext.
/// When disposed, disposes Serilog property push token and invalidates stored value so new log messages are no longer
/// supressed.
/// </remarks>
public static IDisposable SuppressLogging()
{
return new SuppressLoggingDisposableToken();
}
/// <summary>
/// Determines whether the given log event suppressed.
/// </summary>
/// <remarks>
/// Also removes "SuppressLogging" property if present.
/// </remarks>
public static Boolean IsSuppressed(this LogEvent logEvent)
{
Boolean containsProperty = logEvent.Properties.TryGetValue(SuppressLoggingProperty, out var val);
if (!containsProperty)
return false;
logEvent.RemovePropertyIfPresent(SuppressLoggingProperty); //No need for that in logs
if (val is ScalarValue scalar && scalar.Value is Guid id)
return ActiveSuppressions.Contains(id);
return false;
}
/// <summary>
/// Disposable wrapper around logging supression property push/pop and value generation/invalidation.
/// </summary>
private class SuppressLoggingDisposableToken : IDisposable
{
private readonly IDisposable _pushPropertyDisposable;
private readonly Guid _guid;
public SuppressLoggingDisposableToken()
{
_guid = Guid.NewGuid();
_pushPropertyDisposable = LogContext.PushProperty(SuppressLoggingProperty, _guid);
ActiveSuppressions.Add(_guid);
}
public void Dispose()
{
ActiveSuppressions.Remove(_guid);
_pushPropertyDisposable.Dispose();
}
}
}
The complete example project can be found on github.
I would like to leave this self-answered question here and also to ask more experienced Serilog users what their opinion of this problem is. May be there is some common approach to logging suppression I didn't find?
I would like to add to ArXen42 answer.
The proposed Hashset to keep track of the the activesuppression keys is not threadsafe and will create issues when using multiple threads.
A solution would be to use the ConcurrentDictionary<T,T2> instead of the HashSet<T> or the solution as stated below without keeping track of GUIDs to supress the logs.
/// Provides helper extensions to Serilog logging.
/// </summary>
public static class SerilogExtensions
{
private const string SuppressLoggingProperty
= "SuppressLogging";
/// <summary>
/// Get disposable token to supress logging for context.
/// </summary>
public static IDisposable SuppressLogging()
{
return LogContext.PushProperty(SuppressLoggingProperty, true);
}
/// <summary>
/// Determines whether the given log event suppressed.
/// </summary>
/// <remarks>
/// Also removes "SuppressLogging" property if present.
/// </remarks>
public static bool IsSuppressed(this LogEvent logEvent)
{
var containsProperty = logEvent.Properties
.TryGetValue(SuppressLoggingProperty, out var val);
if (!containsProperty)
return false;
// remove suppression property from logs
logEvent.RemovePropertyIfPresent(SuppressLoggingProperty);
if (val is ScalarValue scalar && scalar.Value is bool isSuppressed)
return isSuppressed;
return false;
}
}

AOP Ninject Stop Intercepted Method From Being Called

I'm using Ninject and AOP to do some caching. I have a Attribute that I can apply to any method in my repository and on BeforeInvoke it will return my cached Object if there is one and AfterInvoke create a cached object. This all works great but I can't figure out how to stop initial method from being called, ie if there is a cached object the return that instead of calling a the intyercepted method. My interceptor is here:
public class CacheInterceptor : SimpleInterceptor
{
protected override void BeforeInvoke(IInvocation invocation)
{
Type returnType = invocation.Request.Method.ReturnType;
string cacheKey = CacheKeyBuilder.GetCacheKey(invocation, serializer);
object cachedValue = cache.Get(cacheKey);
if (cachedValue == null)
{
invocation.Proceed();
}
else
{
object returnValue = serializer.Deserialize(returnType, cachedValue);
invocation.ReturnValue = returnValue;
returnedCachedResult = true;
}
}
}
Even though in the else statement I am clearly not saying to call the invoked Method 'invocation.Proceed();' it still invokes it. How do I tell ninject to just return with the invocation.ReturnValue ?
You can't use SimpleInterceptor in this case because that is meant as base class for the most common scenario where you want to do an action before or after the actual method call. Also you are not allowed to call Proceed Instead implement the IInterceptor interface and put your code into the Intercept method.
But probably we should extend SimpleInterceptor in a future version so that you can prevent that the actual method is called:
public abstract class SimpleInterceptor : IInterceptor
{
private bool proceedInvocation = true;
/// <summary>
/// Intercepts the specified invocation.
/// </summary>
/// <param name="invocation">The invocation to intercept.</param>
public void Intercept( IInvocation invocation )
{
BeforeInvoke( invocation );
if (proceedInvocation)
{
invocation.Proceed();
AfterInvoke( invocation );
}
}
/// <summary>
/// When called in BeforeInvoke then the invokation in not proceeded anymore.
/// Or in other words the decorated method and AfterInvoke won't be called anymore.
/// Make sure you have assigned the return value in case it is not void.
/// </summary>
protected void DontProceedInvokation()
{
this.proceedInvocation = false;
}
/// <summary>
/// Takes some action before the invocation proceeds.
/// </summary>
/// <param name="invocation">The invocation that is being intercepted.</param>
protected virtual void BeforeInvoke( IInvocation invocation )
{
}
/// <summary>
/// Takes some action after the invocation proceeds.
/// </summary>
/// <param name="invocation">The invocation that is being intercepted.</param>
protected virtual void AfterInvoke( IInvocation invocation )
{
}
}

Return a string from a Service already running using Remoting

im trying to use .Net Remoting to get a value of a variable that i use in a thread of an windows service.
TcpChannel tcpChannel = new TcpChannel(9998);
ChannelServices.RegisterChannel(tcpChannel, false);
Type commonInterfaceType = typeof(MyNameSpace.Core.Engine);
RemotingConfiguration.RegisterWellKnownServiceType(commonInterfaceType,
"CopyFilePercentage",
WellKnownObjectMode.SingleCall);
myEngine = Engine.EngineInstance;
myEngine.Start();
But it seams that every time that i use the Client to get that value, a new thread is created returning an empty string.
Any idea why is this happening or am I doing something wrong?
Thanks in advance,
Miguel de Sousa
WellKnownObjectMode.SingleCall creates a new instance of your class for each call. try WellKnownObjectMode.Singleton
EDIT
Maybe you should read about client activated objects. Turn your singleton object to a class factory and return a new instance of a real worker class(ofcourse inheriting from MarshalByRefObject) which will be used by the client.
so your client will be something like this
var worker = client.GetWorkerClass();
worker.GetSomeData();
and you will have one server object per connection (this may not be the correct terminology).
well i just used a Global Variable Class not really what I wanted but does the job.
/// <summary>
/// Contains global variables for project.
/// </summary>
public static class GlobalVar
{
/// <summary>
/// Global variable that is constant.
/// </summary>
public const string GlobalString = "Important Text";
/// <summary>
/// Static value protected by access routine.
/// </summary>
static int _globalValue;
/// <summary>
/// Access routine for global variable.
/// </summary>
public static int GlobalValue
{
get
{
return _globalValue;
}
set
{
_globalValue = value;
}
}
/// <summary>
/// Global static field.
/// </summary>
public static bool GlobalBoolean;
}

Moq a proxy for unit testing

I'm new to using Moq and I cannot find the way for doing this.
I've a generateId private method, called
/// <summary>
/// Generates a call Id for external interfaces
/// </summary>
/// <returns></returns>
private string GenerateCallId()
{
return "EX" + SharedServicesClientProxy.Instance.GenerateId().ToString();
}
I wanted to unit test this method, and for that reason i need to mock the Proxy.
SharedServicesClientProxy is just an object that implements the interface ISharedServices but adds the singleton. I wanted to test that all the strings correctly returned a string starting with "EX". this is my unit test, using Moq
/// <summary>
/// A test for GenerateCallId
/// A CallId for external systems should always start by "EX"
///</summary>
[TestMethod()]
[DeploymentItem("myDll.dll")]
public void GenerateCallIdTest()
{
myService_Accessor target = new myService_Accessor();
var SharedServicesClientProxy = new Mock<ISharedServices>();
SharedServicesClientProxy.Setup(x => x.GenerateId()).Returns(5396760556432785286);
string actual;
string extCallIdPrefix = "EX";
actual = target.GenerateCallId();
Assert.IsTrue(actual.StartsWith(extCallIdPrefix));
}
I guess I'm doing my mock in the wrong place?
In a more general way, how do i mock an object that is going to be called by the method I'm testing?
for eg:
/// <summary>
/// dummy test
///</summary>
[TestMethod()]
[DeploymentItem("myDll.dll")]
public void Foo()
{
myService_Accessor target = new myService_Accessor();
boolexpected = false;
actual = target.Foo();
Assert.IsTrue(actual,expected);
}
/// <summary>
/// Foo
/// </summary>
/// <returns></returns>
private bool Foo()
{
return this.Bar();
}
I need to moq Bar, but where do i need to do it?
Thanks,
Seb
Search for the term "Dependency Injection" before proceeding.
You have a dependency on SharedServicesClientProxy.Instance, which is a Singleton. This will cause problems with test isolation, since you will reuse the same instance across tests and be prone to state-leftover issues.
I'd advise to inject dependencies like this (and OT- you shouldn't be testing private methods... test via the public interface. There it is out of my system..:)
public class AnonClass
{
ISharedServices _sharedServices;
AnonClass(ISharedServices sharedServicesObj)
{
_sharedServices = sharedServicesObj;
}
public string GenerateCallId()
{
return "EX" + _sharedServices.GenerateId().ToString();
}
}
Rewire your current code to create the target class like this
var class = new AnonClass(SharedServicesClientProxy.Instance);
In your test, pass in the mock object instead of the object returned by the Singleton

Categories