C# UnitTest void static method - c#

I'm trying to make an unit test for a logger in an application.
For example I need to test the method Logger.info("some message"), but this method is static and return void.
Searching on Google I understand that I have to use Moq but am unable to implement that on the UnitTest class.
The Logger constructor does not have an argument and in x.Debug I have an error that says that I can't access
from instance reference.
Is there a way to implement UnitTest without editing the production code?
[TestClass()]
public class LoggerTests
{
[TestMethod()]
public void DebugTest()
{
var mock = new Mock<Logger>();
mock.Setup(x => x.Debug(It.IsAny<string>());
new Logger(mock.Object).AddLog("testing");
mock.VerifyAll;
}
}
Program.cs
private static void ConfigureLogger()
{
Logger.AddLog(new NLogAppender());
Logger.Level = TraceLevel.Verbose;
Logger.Info("Configured Logger");
}
Logger.cs
public class Logger
{
public static readonly List<IAppender> loggings = new List<IAppender>();
public static void AddLog(IAppender appender)
{
loggings.Add(appender);
}
public static TraceLevel Level { get; set; }
static Logger()
{
Level = TraceLevel.Verbose;
}
public static void Info(string message)
{
LogMessage(message);
}
}
NlogAppender.cs
public class NLogAppender : IAppender
{
public NLog.Logger logger;
public NLogAppender()
{
logger = LogManager.GetLogger(nameof(NLogAppender));
}
public void AddLog(string str)
{
}
}
IAppender.cs
public interface IAppender
{
void AddLog(string str);
}

You can't mock a static class, and you shouldn't mock the class/system under test.
Add a mock appender to the logger:
// Arrange
var logString = "test-info"
var appenderMock = new Mock<IAppender>();
appenderMock.Setup(a => a.AddLog(logString));
Logger.AddLog(appenderMock.Object);
// Act
Logger.Info(logString);
// Assert
// TODO: exactly once
appenderMock.VerifyAll();
Note this static class may persist data between tests causing unexpected results, consult your test framework for configuring this.
Apart from that, you usually don't want to roll your own logging infrastructure, there's lots of things you can do wrong and why reinvent the wheel? Plenty of ILogger(<T>) implementations around.

Related

Test method with param Action<T> with Nunit and Moq c#

I'm using c#, Nunit and Moq and I want to test a method like the Remove() method, that call another method with an Action<> parameter.
public class Db
{
private readonly IMessageWrapper _messageWrapper;
private readonly IProvider _provider;
public Db(IMessageWrapper messageWrapper, IProvider provider)
{
_messageWrapper = messageWrapper;
_provider = provider;
}
public void Remove()
{
Execute(transaction =>
{
// Do something
// method to verify with unit test
_messageWrapper.SendData();
});
}
private void Execute(Action<SqlTransaction> action)
{
_provider.ExecuteAction(action);
}
}
I'd like to do something like:
public class DbTest
{
[Test]
public void Remove_Should_SendData()
{
//... create IMessageWrapper mock and IProvider mock...
var db = new Db(messageWrapperMock.Object, provider.Object);
provider.Setup(p => p.ExecuteAction(It.IsAny<Action<SqlTransaction>>));
db.Remove();
messageWrapperMock.Verify(m => m.SendData(), Times.Once());
}
}
But it doesn't work. The unit test doesn't reach the _messageWrapper.SendData();
Thanks for the help
When you setup without any code - that method does nothing, but you need it to call your action.
Try this:
provider.Setup(p => p.ExecuteAction(It.IsAny<Action<SqlTransaction>>()))
.Callback<Action<SqlTransaction>>(c => c(null));

Nsubstitute executing Action as parameter on a mocked interface

Is there anyway I can execute an action as a parameter from a mocked out service?
I have an interface that is used in the method I am unit testing:
interface IMyTracker
{
void TrackerMethod(string name, Action action);
}
This is the method I want to unit test:
private void Method1(IMyTracker myTracker)
{
myTracker.TrackerMethod("Method1",() =>
{
// This is stuff I want to execute!
}
}
Here is my unit test
[Test]
public void TestMethod1()
{
var trackerSub = Substitute.For<IMyTracker>();
trackerSub.TrackerMethod(Arg.Any<string>(), Arg.Invoke<Action>()); //How do I execute the logic inside the lambda expression action? Is it at all possible? Or once it's mocked, is that logic lost?
GetClassInstance().Method1(trackerSub);
}
Any help here would be great.
i created example code which show you how it works.
So at the start we get you interface:
public interface ITracker
{
void TrackerMethod(string name, Action action);
}
Next we got the sample class which use this interface and do any action in the tracker, look here:
public class AnyClass
{
private readonly ILogger _anyLogger;
public AnyClass(ILogger anyLogger)
{
this._anyLogger = anyLogger;
}
public void AnyMethod(ITracker tracker)
{
tracker.TrackerMethod("mymethod", () =>
{
_anyLogger.LogError("i was here");
});
}
}
and the unit test for this scenario can look like:
[Fact]
public void TestMethod1()
{
var logger = Substitute.For<ILogger>();
var tracker = Substitute.For<ITracker>();
tracker.TrackerMethod(Arg.Any<string>(), Arg.Invoke());
AnyClass anyClass = new AnyClass(logger);
anyClass.AnyMethod(tracker);
logger.Received().LogError("i was here");
}

Injection into Console Application with the Simple Injector

I am using Simple Injector for test purpose but pretty new on OOP. I am trying to create loosely couple classes. Here is the my scenario.
I have User repo and interface like this.
public class UserRepository : IUserRepository
{
public void Add(Model.User user)
{
Console.WriteLine("Name:"+user.Name+"\n"+"SurName:"+user.SurName);
}
public void Delete(int id)
{
throw new NotImplementedException();
}
}
public interface IUserRepository
{
void Add(User user);
void Delete(int id);
}
My TestInjectedClass Class and interface are something like this which I am planning to use in Program Main.
public class TestInjectedClass : ITestInjectedClass
{
private readonly IUserRepository _userRepository;
public TestInjectedClass(IUserRepository userRepository)
{
_userRepository = userRepository;
}
public void UserRepoRun()
{
var user = new User() {Id = 1,Name = "ada",SurName = "stack"};
_userRepository.Add(user);
}
}
public interface ITestInjectedClass
{
void UserRepoRun();
}
And My console program looks like this:
class Program
{
static ITestInjectedClass _testInjectedClass;
private static IUserRepository _userRepository;
static void Main(string[] args)
{
_testInjectedClass= new TestInjectedClass(_userRepository);
_testInjectedClass.UserRepoRun();
Console.ReadLine();
}
public Program()
{
Bootstrap.Start();
}
}
BootStrap class here:
class Bootstrap
{
public static void Start()
{
var container = new Container();
// Register your types, for instance:
container.Register<IUserRepository, UserRepository>(Lifestyle.Singleton);
container.Register<ITestInjectedClass, TestInjectedClass>(Lifestyle.Singleton);
//container.Register<IUserRepository, TestInjectedClass>(Lifestyle.Singleton);
//container.Register<IUserContext, WinFormsUserContext>();
container.Register<TestInjectedClass>();
// Optionally verify the container.
container.Verify();
}
}
My problem when I run program, I am getting a value exception on the _userRepository inside TestInjectionClass.
How can I properly inject TestInjectionClass and UserRepository to Main Program. Thanks
You need to make Bootstrap.container available in Program.Main and then use it to create instances of classes instead of directly calling their constructors directly:
_testInjectedClass = Bootstrap.container.GetInstance<ITestInjectedClass>();
Of course you will need to expose it in Bootstrap for that to work:
class Bootstrap
{
public static Container container;
public static void Start()
{
container = new Container();
// Register your types, for instance:
container.Register<IUserRepository, UserRepository>(Lifestyle.Singleton);
container.Register<ITestInjectedClass, TestInjectedClass>(Lifestyle.Singleton);
//container.Register<IUserRepository, TestInjectedClass>(Lifestyle.Singleton);
//container.Register<IUserContext, WinFormsUserContext>();
container.Register<TestInjectedClass>();
// Optionally verify the container.
container.Verify();
}
}
And call Bootstrap.Start from Program.Main:
static void Main(string[] args)
{
Bootstrap.Start();
_testInjectedClass = Bootstrap.container.GetInstance<ITestInjectedClass>();
_testInjectedClass.UserRepoRun();
Console.ReadLine();
}
The problem is because you are calling your Bootstrap code in Program class instance constructor.
So, actually when you start your program the execution environment, is calling entry point method Main. And your instance constructor is never executed.
Try changing your entry point method Main and 'Bootstrap' class code:
static void Main(string[] args)
{
var container = new Container();
Bootstrap.Start(container);
_testInjectedClass = container.GetInstance<TestInjectedClass>();
_testInjectedClass.UserRepoRun();
Console.ReadLine();
}
class Bootstrap
{
public static void Start(Container container)
{
// Register your types, for instance:
container.Register<IUserRepository, UserRepository>(Lifestyle.Singleton);
container.Register<ITestInjectedClass, TestInjectedClass>(Lifestyle.Singleton);
container.Register<TestInjectedClass>();
// Optionally verify the container.
container.Verify();
}
}
Please use SimpleInjector
Sample please refer
http://www.c-sharpcorner.com/UploadFile/4d9083/dependency-injection-using-simple-injector/

ServiceStack integration tests: ServiceStackHost.Instance has already been set

I am writing integration tests for ServiceStack with in-memory database and I ran into this exception: "System.IO.InvalidDataException ServiceStackHost.Instance has already been set" while trying to run multiple test classes together, each having its own AppHostHttpListenerBase. However, if I ran the test classes one at a time, it ran and passed without problems. One reason for having multiple classes is because I want to test the AppHost with different services/dependencies registered and also to group my tests logically. Below is a general snippet of my tests. I would like to be able run all the test at one go.
public class TestClassOne : IDisposable
{
string _endPoint = "http://localhost:54321/";
AppHostHttpListenerBase _appHost;
IDbConnectionFactory _dbConn = new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider);
public TestClassOne()
{
_appHost = new UnitTestAppHost(_dbConn, ...){};
_appHost.Init().Start(_endPoint);
}
[Fact]
public void Test()
{
...
using(var db = _dbConn.Open())
{
Assert.True(...);
}
}
public void Dispose()
{
_appHost.Dispose();
_appHost = null;
}
}
public class TestClassTwo : IDisposable
{
string _endPoint = "http://localhost:54321/";
AppHostHttpListenerBase _appHost;
IDbConnectionFactory _dbConn = new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider);
public TestClassTwo()
{
_appHost = new UnitTestAppHost(...){};
_appHost.Init().Start(_endPoint);
}
[Fact]
public void Test()
{
...
using(var db = _dbConn.Open())
{
Assert.True(...);
}
}
public void Dispose()
{
_appHost.Dispose();
_appHost = null;
}
}
I have tried running on another AppDomain, but it doesn't seems to be what I am looking for I think, because I need to do some Asserts on IDbConnection in the current running AppDomain (?), if that make any sense. Any suggestions on how I should be doing it? I'm using xUnit and Resharper's test runner btw.
I ended up fixing this by creating an AppHostSetupFixture class with a public static AppHost variable. Create a [SetUp] method that initializes your app host and a [TearDown] method that disposes it. Use AppHostSetupFixture.AppHost in your test classes.
[SetUpFixture]
public class AppHostSetupFixture
{
public static ServiceStackHost AppHost;
[SetUp]
public void Setup()
{
AppHost = new BasicAppHost(typeof(FeatureService).Assembly)
{
ConfigureContainer = container =>
{
var l = new List<string>();
l.Add(ConfigurationManager.ConnectionStrings["Redis"].ConnectionString);
container.Register<IRedisClientsManager>(c => new RedisManagerPool(l, new RedisPoolConfig() { MaxPoolSize = 40 }));
}
}
.Init();
}
[TearDown]
public void TearDown()
{
AppHost.Dispose();
}
}
This error is a result of trying to run multiple AppHosts per AppDomain. Each ServiceStack AppHost is a singleton and only allows a single AppHost per AppDomain.

Programmatic configuration of Enterprise Library logging block

I've previously used log4net, but my current employer uses Enterprise Library application blocks. I had previously developed unit tests for my core logging classes as follows and was wondering if someone knew the equivalent for the OneTimeSetup code below for the logging app block (sorry for the long code post):
public abstract class DataGathererBase
{
public readonly log4net.ILog logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public void CollectData()
{
this.LogDebug("Initialize started");
}
public static class Logger
{
private static LoggingSettings settings = LoggingSettings.GetLoggingSettings(new SystemConfigurationSource());
static Logger()
{
log4net.Config.XmlConfigurator.Configure();
}
public static void LogDebug(this DataGathererBase current, string message)
{
if (current.logger.IsDebugEnabled)
{
current.logger.Debug(string.Format("{0} logged: {1}", current.GetType().Name, message));
}
}
}
[TestFixture]
public class LoggerTests:DataGathererBase
{
private ListAppender appender;
private static ILog log;
[TestFixtureSetUp]
public void OneTimeSetup()
{
appender = new ListAppender();
appender.Layout = new log4net.Layout.SimpleLayout();
appender.Threshold = log4net.Core.Level.Fatal;
log4net.Config.BasicConfigurator.Configure(appender);
log = LogManager.GetLogger(typeof(ListAppender));
}
[Test]
public void TestLogging()
{
this.LogDebug("Debug");
Assert.AreEqual(0, ListAppender.logTable.Count());
}
}
Enterprise Library 5.0 introduced a fluent interface which can be used to programmatically configure the application blocks. You will probably find this to be a more comfortable option.
To give credit, this answer is based on a David Hayden article which is based on an Alois Kraus article, Programatic Configuraton - Enterprise Library (v2.0) Logging Block . Read those two articles for a good look at programmatic access to Enterprise Library logging.
I wasn't familiar with ListAppender so I created a CustomTraceListener that sticks the log messages in a List<string>:
public class ListAppender : Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.CustomTraceListener
{
private List<string> list = new List<string>();
public override void Write(string message)
{
}
public override void WriteLine(string message)
{
list.Add(message);
}
public List<string> LogTable
{
get
{
return list;
}
}
}
Here is a modified LoggerTests class that programmatically accesses the EL logging classes to setup the tests (this does not use NUnit):
public class LoggerTests
{
private ListAppender appender;
private static LogWriter log;
public void OneTimeSetup()
{
appender = new ListAppender();
// Log all source levels
LogSource mainLogSource = new LogSource("MainLogSource", SourceLevels.All);
mainLogSource.Listeners.Add(appender);
// All messages with a category of "Error" should be distributed
// to all TraceListeners in mainLogSource.
IDictionary<string, LogSource> traceSources = new Dictionary<string, LogSource>();
traceSources.Add("Error", mainLogSource);
LogSource nonExistentLogSource = null;
log = new LogWriter(new ILogFilter[0], traceSources, nonExistentLogSource,
nonExistentLogSource, mainLogSource, "Error", false, false);
}
public void TestLogging()
{
LogEntry le = new LogEntry() { Message = "Test", Severity = TraceEventType.Information };
le.Categories.Add("Debug");
log.Write(le);
// we are not setup to log debug messages
System.Diagnostics.Debug.Assert(appender.LogTable.Count == 0);
le.Categories.Add("Error");
log.Write(le);
// we should have logged an error
System.Diagnostics.Debug.Assert(appender.LogTable.Count == 1);
}
}

Categories