How to mock static methods in c# using MOQ framework?
Moq (and other DynamicProxy-based mocking frameworks) are unable to mock anything that is not a virtual or abstract method.
Sealed/static classes/methods can only be faked with Profiler API based tools, like Typemock (commercial) or Microsoft Moles (free, known as Fakes in Visual Studio 2012 Ultimate /2013 /2015).
Alternatively, you could refactor your design to abstract calls to static methods, and provide this abstraction to your class via dependency injection. Then you'd not only have a better design, it will be testable with free tools, like Moq.
A common pattern to allow testability can be applied without using any tools altogether. Consider the following method:
public class MyClass
{
public string[] GetMyData(string fileName)
{
string[] data = FileUtil.ReadDataFromFile(fileName);
return data;
}
}
Instead of trying to mock FileUtil.ReadDataFromFile
, you could wrap it in a protected virtual
method, like this:
public class MyClass
{
public string[] GetMyData(string fileName)
{
string[] data = GetDataFromFile(fileName);
return data;
}
protected virtual string[] GetDataFromFile(string fileName)
{
return FileUtil.ReadDataFromFile(fileName);
}
}
Then, in your unit test, derive from MyClass
and call it TestableMyClass
. Then you can override the GetDataFromFile
method to return your own test data.
Hope that helps.
Mock Static class using moq
There are two ways to accomplish this - As PSGuy said you can create an Interface that your code can rely on, then implement a concrete that simply calls the static method or any other logging implementation like NLog. This is the ideal choice. In addition to this if you have lots of code calling the static method that needs to be tested you can refactor your static method to be mocked.
Assuming your static class looks something like this:
public static class AppLog
{
public static void LogSomething(...) { ... }
}
You can introduce a public static property that is an instance of the Interface mentioned above.
public static class AppLog
{
public static ILogger Logger = new Logger();
public static void LogSomething(...)
{
Logger.LogSomething(...);
}
}
Now any code dependent on this static method can be tested.
public void Test()
{
AppLog.Logger = Substitute.For<ILogger>(); // NSubstitute
var logMock = new Mock<ILogger>(); // Moq
AppLog.Logger = logMock.Object; // Moq
SomeMethodToTest();
AppLog.Logger.Recieved(1).LogSomething(...); // NSubstitute
logMock.Verify(x => x.LogSomething(...)); // Moq
}
Mocking Static Methods
Mocking frameworks like Moq or Rhinomocks can only create mock instances of objects, this means mocking static methods is not possible.
You can also search Google for more info.
Also, there's a few questions previously asked on StackOverflow here, here and here.
Moq a static method in static class
Moq doesn't allow the mocking of static methods so you will probably need to change the working of the static method. One option is to have the static method call an instance method of a dependency. So you'll create a "Logger" class with a Log method and add a static Logger field / property (BusinessExceptionHandler.Logger) to your static class. In the real-world scenario you can populate BusinessExceptionHandler.Logger with a standard Logger instance, using it as a Singleton. For testing, inject a Mock into the BusinessExceptionHandler.Logger and set up your expectations and verify against the mock.
Related Topics
Mvc/Jquery Validation Does Not Accept Comma as Decimal Separator
Wpf: How to Loop Through the All Controls in a Window
Is Nameof() Evaluated at Compile-Time
C# an Established Connection Was Aborted by the Software in Your Host MAChine
Formatting a Double to Two Decimal Places
Entity Framework Error: Cannot Insert Explicit Value for Identity Column in Table
-Event- Can Only Appear on the Left Hand Side of += or -=
ASP.NET Core Metadatatype Attribute Not Working
Can You Have a Property Name Containing a Dash
Convert from Binary Data to an Image Control in ASP.NET
Can You Specify Format for Xmlserialization of a Datetime
Datagrid Get Selected Rows' Column Values
Is SQLcommand.Dispose() Required If Associated SQLconnection Will Be Disposed
How to Interrupt Console.Readline