Unit test factory method for object with dependencies - c#

I'm new in unit testing.
Its suggested to use Factory method to create instance of class under test for maintainability reasons.
Like:
public class StringCalculatorTests
{
[Fact]
public void Add_EmptyString_ReturnZero()
{
var calculator = CreateCalculator();
int result = calculator.Add("");
result.Should().Be(0);
}
private static StringCalculator CreateCalculator()
{
//Some difficult object creation
var logger = Substitute.For<ILogger>();
var calculator = new StringCalculator(logger);
calculator.Initialize();
return calculator;
}
}
Everything nice: if API changes - i will change StringCalculator creation only in one place, not in every tests.
But what if i need to change a return value for some method of ILogger. Or I will use ILogger not as stub but as a mock:
[Fact]
public void Add_EmptyString_LogAboutEmptyInput()
{
var loggerMock = Substitute.For<ILogger>();
var calculator = new StringCalculator(loggerMock);
calculator.Initialize();
calculator.Add("");
logger.Received("Empty input.");
}
Now i can't use factory method, and if there are changes in API - i should go through my tests to change it.
I thought about property injection - but it may be not good local default for ILogger for example.
(i know - we usually have good default for logger, but it can be some another dependency)
I thought about optional parameters for factory method. But it seems to have logic. It's very simple but still logic.
Is there any good approach to solve this? Or it's good enough and it's a common situation to create instance just in class when we need it?

You can overload your factory method to accept a mock logger.
private static StringCalculator CreateCalculator(ILogger logger)
{
var calculator = new StringCalculator(logger);
calculator.Initialize();
return calculator;
}
Then you can create your mock logger in the test (possibly a separate factory method for the logger if the same mocking is used in multiple tests)
[Fact]
public void Add_EmptyString_LogAboutEmptyInput()
{
var loggerMock = //whatever code you need to set up your mock
var calculator = CreateCalculator(loggerMock);
calculator.Add("");
logger.Received("Empty input.");
}

Related

Mocking a method that takes a mocked parameter object in C#

The to be tested method
public string GetPopulatedField(string input)
{
IParameterCollection sqlParams = CreateParameterCollection();
sqlParams.Add("param", input);
string recordCollection = DataAccess.ExecuteSelect(SQL, ref sqlParams);
return recordCollection ;
}
The test method
public void Test()
{
// Mocking one of the dependencies used by the ExecuteSelect
MockHelper.CreateAndRegisterMock<IParameterCollection>();
Mock<Access> mock = new Mock<Access>();
//mocking the ExecuteSelect Method that takes a string and and IParameterCollection
mock.Setup(t => t.ExecuteSelect(It.IsAny<string>(),ref It.Ref<IParameterCollection>.IsAny)).Returns("123");
//The execute Select is called from the GetPopulatedField method
var x= MockHelper.CreateAndRegisterMock<PopulateField>("Container");
Assert.AreEqual("123", x.Object.GetPopulatedField("value"));
}
The issue is when ExecuteSelect is called from GetPopulateField it is using the Mock object and not the actual IParameterCollection, so what is the correct way to Mock the ExecuteSelect properly?
ref It.Ref<IParameterCollection>.IsAny I believe this should be changed to reflect the mocked one.
In a unit test, it is important to only test a unit, a small portion of code. The smaller the unit,
the easier the reason can be found if a failure occurs.
the faster the tests can be run.
In order to reduce the code to the relevant unit, two aspects are important:
you want to test the real code of the unit as it would be used in the program flow - hence you create a real instance of the class you want to test, not a mock.
you do not want to test code that the unit depends on - therefore
you structure your code in a way that you can replace dependencies with mocks and
you create mocks for the dependencies when testing.
With that in mind, you could change your PopulateField class like this:
public class PopulateField
{
private readonly IDataAccess _dataAccess;
public PopulateField(IDataAccess dataAccess)
{
_dataAccess = dataAccess;
}
public string GetPopulatedField(string input)
{
IParameterCollection sqlParams = CreateParameterCollection();
sqlParams.Add("param", input);
string recordCollection = _dataAccess.ExecuteSelect(SQL, ref sqlParams);
return recordCollection;
}
// ...
}
With an instance of type IDataAccess injected into the constructor and used in the GetPopulatedFields method, you can easily replace it with a mock in the tests:
public void Test()
{
// Create a mock for the data access
Mock<IDataAccess> mockDataAccess = new Mock<IDataAccess>();
//mocking the ExecuteSelect Method that takes a string and and IParameterCollection
mockDataAccess.Setup(t => t.ExecuteSelect(It.IsAny<string>(),ref It.Ref<IParameterCollection>.IsAny())).Returns("123");
// Create an instance of PopulateFields so the tests run on real code
var pf = new PopulateFields(mockDataAccess.Object);
var actual = pf.GetPopulatedFields("input");
Assert.AreEqual("123", actual);
}
Please note that the creation of the IParameterCollection happens in a method of PopulateFields that you cannot replace with this behavior. There are two ways to go about this:
If it is important to also mock the instantiation of the ParameterCollection, you need to create a factory interface that contains a method that returns the IParameterCollection instance. Along with IDataAccess an instance implementing this interface is also injected into the constructor of PopulateFields so you can replace it with a mock when testing.
If you only want to validate that the correct parameters are set when GetPopulatedFields is called, you can add a validation to the setup. Unfortunately, for It.Ref<T> there is only a IsAny and no Is method that allows deciding whether the parameters match, so we solve it with a callback:
mock.Setup(t => t.ExecuteSelect(It.IsAny<string>(),ref It.Ref<IParameterCollection>.IsAny)).Callback((string s, ref IParameterCollection params) => {
if (!params.Contains("param")) // Adjust conditions to IParameterCollection
throw new ApplicationException("Parameter was not added");
}.Returns("123");

Unit Test - How to test a `void` method that just inserts a log message (Serilog)

I need to test a method of type void, it just inserts a message on my LOG variable using a LOG framework (Serilog).
See the implementation example:
public class MyClass
{
public MyClass(ILogger<IProcess> logger)
{
this.logger = logger;
}
private readonly ILogger logger;
//...Anothers methods...
public void LogInit(Guid processId, string folder, string[] args)
{
var myObject = new
{
ProcessId = processId,
Folder = folder,
Arguments = args
};
this.logger.LogWarning("{#myObject}", myObject);
}
}
In this scenario, we would need to create a test for the LogInit (...)
Does this method really need to be tested? Or rather, does it make sense for it to exist?
I was reading something about:
"If your method has no side effects, and doesn’t return anything, then it’s not doing anything."
In this case, the method was only created "separately" to maintain the organization of the code and separate the responsibilities of the class a bit more.
That makes sense?
EDIT: #PeterBons
We do not have access to the messages registered in the Interface (logger), like: this.logger.GiveMeWarningLogs()...
If you're using Serilog, you can use the Test Correlator Sink to see what log events a method call produced.
[TestMethod]
public void A_test()
{
var myClass = new MyClass(new LoggerConfiguration().WriteTo.TestCorrelator().CreateLogger());
using (TestCorrelator.CreateContext())
{
myClass.LogInit();
TestCorrelator.GetLogEventsFromCurrentContext()
.Should().ContainSingle()
.Which.MessageTemplate.Text
.Should().Be("{#myObject}");
}
}
You have to mock your logger and check whether LogWarning method was called. You can use Moq for this. Also if you want to test LogInit you need to make this public or internal with defining [InternalVisibleTo('someTestProjName')]
Test method will looks like this (xUnit):
public void ShouldCallLogWarning()
{
var loggerMock = new Mock<ILogger>();
loggerMock.Setup(_ => _.LogWarning(It.IsAny<string>(), It.IsAny<object>(), null);
var myClass = new MyClass(loggerMock.Object);
//
myClass.LogInit(Guid.NewGuid(), "folderPath", null)
//
_loggerMock.Verify(_ => _.LogWarning(It.IsAny<string>(), It.IsAny<string>(), null), Times.Once());
}
Your method is not returning anything so it would be harder to test if for sure.
Right now the only thing your method does is prepare the logged object for the Serilog library. If you had more complicated logic for the creation of that object you could extract it into it's own method and have it return that log object then it would be easy to test that instead. The benefit of the method you have created is that it creates an extra layer so that if you decide to change the logging library you would only do it in one place.

Mock Log Singleton in Unit Test

I have a logger class, which purpose is to be called from whatever class in my solution, who decides to log something.
I added an interface, which is why I applied a singleton pattern, and didn't use a static class.
My LogManager implementation (singleton):
https://pastebin.com/NHKmbj9c
I wanted to write simple unit tests, which are supposed to use local variables, testing the functionality of each ILogger methods, but as soon as my first Unit has passed, the Singleton will stay initialized in context, making subsequent unit tests to fail (while they are trying to Initialize the singleton...).
Unit Test:
[TestClass]
public class LogManagerTests
{
[TestMethod]
public void Error_ExpectedErrorLevel_ShouldBe_Error()
{
// Arrange
var actualLevel = ErrorLevel.Warning;
const ErrorLevel expectedLevel = ErrorLevel.Error;
var iLogger = LogManager.GetInstance;
iLogger.Initialize((level, msg) => { actualLevel = level; }, null);
// Act
iLogger.Error(new Exception(), string.Empty);
// Assert
Assert.AreEqual(expectedLevel, actualLevel);
}
[TestMethod]
public void Debug_ExpectedErrorLevel_ShouldBe_Verbose()
{
// Arrange
var actualLevel = ErrorLevel.Warning;
const ErrorLevel expectedLevel = ErrorLevel.Verbose;
var iLogger = LogManager.GetInstance;
iLogger.Initialize(null, (level, msg, ex) => { actualLevel = level; });
// Act
iLogger.Debug(string.Empty);
// Assert
Assert.AreEqual(expectedLevel, actualLevel);
}
}
Another tought is to initialize the LogManager as a private global variable within my TestClass, but this could give race conditions if the Unit test runs async, as multiple methods then will access the same output variable, which may override each others.
Is it possible to UnitTest a singleton in any way?
The design does not allow me to refactor the LogManager, and remove the singleton pattern from it.
It's possible to unit test a singleton, you just need to think about it differently. Don't try so hard to change your methodology to fit the test. Think about creating a method that is used only for testing, LogManager.Uninitialize().
Call this after every test in this group of tests to ensure your singleton is set back to a testable state.
[TestCleanup()]
public void Cleanup()
{
LogManager.Uninitialize();
}
It may not be pure but I think it's fine to write in a diagnostics method every once in a while. It's better than having bad test coverage where you need good test coverage.

Mock Unit Testing - Getting details of the classes implementing interface

I have a User Interface lets call it IUser.
There are two implementations of this: AdminUser and NormalUser.
Now, I am trying to use these user classes via Unit Testing(Mocking).
I mock the interface as follows:
var mockUser = new Mock<IUser>();
mockUser.get("username");
I have added breakkpoints throughout the classes but I am not sure which instance of the interface is getting called i.e AdminUser or NormalUser.
It never stops at the debug points and no clue from the mockUser instance.
How can I get the details of the class being called by the mockUser mock instance?
Thanks in advance.
Creating a Mock<IUser> actually creates a new implementation of IUser. So it won't help you to test any of your actual implementations.
Using a Mock works something like this:
Suppose I have this class and interface. The class validates whether a postal code is valid for a country. It depends on another interface which provides the regex pattern for the given country.
public class PostalCodeValidator
{
private readonly IPostalCodeRegexProvider _regexProvider;
public PostalCodeValidator(IPostalCodeRegexProvider regexProvider)
{
_regexProvider = regexProvider;
}
public bool ValidatePostalCode(string postalCode, string countryCode)
{
var regex = _regexProvider.GetPostalCodeRegex(countryCode);
if (string.IsNullOrEmpty(regex)) return true;
return Regex.IsMatch(postalCode, regex);
}
}
public interface IPostalCodeRegexProvider
{
string GetPostalCodeRegex(string countryCode);
}
The implementation of IPostalCodeRegexProvider could be anything. It could call a database, it could be hard-coded.
But when I write unit tests for PostalCodeValidator, I explicitly don't want to test a real implementation of IPostalCodeRegexProvider. I want to make IPostalCodeValidator return exactly what I want so that I can make sure that PostalCodeValidator works. I'm only testing PostalCodeValidator.
If I want to test that ValidatePostalCode returns true when IPostalCodeRegexProvider.GetPostalCode returns null, then I need to make sure that it will return null. That's where the Mock comes in.
It allows me to easily create an implementation of IPostalCodeRegexProvider that will always return null, so I can test what ValidatePostalCode does with that null.
[TestMethod]
public void ValidatePostalCode_ReturnsTrueWhenRegexIsNull()
{
var mock = new Mock<IPostalCodeRegexProvider>();
mock.Setup(x => x.GetPostalCodeRegex(It.IsAny<string>())).Returns(default(string));
var subject = new PostalCodeValidator(mock.Object);
Assert.IsTrue(subject.ValidatePostalCode("xyz","abc"));
}
Whatever the subject of the test is - in this case PostalCodeValidator, or in your case AdminUser and NormalUser - that's what you would create an instance of. If those classes depend on other interfaces then you might create a Mock for each of those interfaces.
You can also consider using a "test double." Instead of using Moq, you just create a simple class that implements the interface. For example, what I did with Moq I could also do like this:
public class PostalCodeRegexProviderThatReturnsNull : IPostalCodeRegexProvider
{
public string GetPostalCodeRegex(string countryCode)
{
return null;
}
}
Now the unit test would look like this:
public void ValidatePostalCode_ReturnsTrueWhenRegexIsNull()
{
var regexProvider = new PostalCodeRegexProviderThatReturnsNull();
var subject = new PostalCodeValidator(regexProvider);
Assert.IsTrue(subject.ValidatePostalCode("xyz","abc"));
}
That is often easier to understand than using a Mock. Sometimes the setup for mocks can get complicated and difficult to read and debug, but a simple class can do the job just as well or even better.
In order to test the actual implementations then you need to initialize the actual implementations i.e. new AdminUser().
For example
[TestMethod]
public void TestAdminUser {
//Arrange
IUser admin = new AdminUser();
//...set any necessary members relevant to the test
//Act
//...invoke member to be tested
//Assert
//...verify actual to expected behavior
}
If either of the implementations have external dependencies then you would mock those (the dependencies) and inject them.
If a class depended on an IUser
public class SomeClass {
private readonly IUser user;
public SomeClass(IUser user) {
this.user = user;
}
//...
}
and you wanted to test that class then you would have a reason to mock IUser for an isolated unit test.
[TestMethod]
public void TestSomeClass {
//Arrange
var username = "dummy";
var expected = "some value";
var mock = new Mock<IUser>();
//...set any necessary members relevant to the test
mock.Setup(_ => _.username).Returns(username);
var subject = new SomeClass(mock.Object);
//Act
//...invoke member to be tested
var actual = subject.SomeMethod();
//Assert
//...verify actual to expected behavior
Assert.AreEqual(actual, expected);
}
Reference Moq Quickstart to get a better understanding of how to use Moq

How to Setup a readonly property with Moq?

I am trying to unit test using Moq. Here is the example code:
public class ConcreteClass
{
private readonly FirstPropery firstProperty;
private readonly SecondProperty secondProperty;
public ConcreteClass(firstProperty, secondProperty)
{
this.firstProperty = firstProperty;
this.secondProperty = secondProperty;
}
}
[TestMethod]
var concreteClassMock = new Mock<ConcreteClass>() { CallBase = true };
In my test method, I want to set firstProperty to reference a real object FirstProperty object (created by a factory), and later use it to test another object's behavior. Is there any way to achieve that?
Usually, you wouldn’t mock private members since you are only mocking the public interface of something. A mock is thus completely independent of implementation details.
That being said, you can pass constructor arguments to the Mock constructor that will then be passed on to the target’s constructor:
new Mock<ConcreteClass>(firstProperty, secondProperty) {CallBase = true};
However, if your goal is to actually test the ConcreteClass, you should not create a mock of it. You should test the actual object. So mock its dependencies and pass those if necessary, but keep the object you want to test actually real. Otherwise, you might introduce and test behavior that comes from the mock instead of the object you are testing:
var firstMock = new Mock<FirstProperty>();
var secondMock = new Mock<FirstProperty>();
var obj = new ConcreteClass(firstMock.Object, secondMock.Object);
obj.DoSomething();
// assert stuff
A few remarks:
1- It could be easily achieve with an interface and a get method like this:
public interface IConcreteClass
{
FirstProperty FirstProperty { get; }
}
[Test]
public void TestCase()
{
var yourFirstPropertyImplementation = new FirstProperty();
var concreteClassMock = new Mock<IConcreteClass>();
concreteClassMock.Setup(o => o.FirstProperty).Returns(yourFirstPropertyImplementation);
}
2- Depending of your scenario, do you really need a Moq, why not just use the true implementation and use moq only at boundaries?
3- You should clarify what you want to test? If it's concrete class? or the properties? or some other classes? The test case I propose in 1 is valid only to test the interaction of concrete class with some other classes.

Categories

Resources