Reputation: 808
The test should test the AddDebug method works correctly. So If the username is null It will automatically set the user name to "Anononymus". However I can't see the List because it's private, therefore the only way to check to function works correctly is take advantage of that opportunity that the AddDebug method calling the Add method. I have to verify that the Add method was called with the "Anonymous" parameter I only can use Nunit, Mock is not optional now for me.
private List<Log> Entries;
public Logger()
{
Entries = new List<Log>();
}
public void Add(string text, LogLevels level, DateTime timeStamp, string userName)
{
var Enitity = new Log();
Enitity.Text = text;
Enitity.Level = level;
Enitity.TimeStamp = timeStamp;
Enitity.UserName = userName;
Add(Enitity);
}
public void Add(Log log)
{
if (!(log.TimeStamp > DateTime.Now))
{
Entries.Add(log);
}
}
public void AddDebug(string text, string userName = null)
{
if (String.IsNullOrEmpty(userName) == true)
{
Add(text, LogLevels.Debug, DateTime.Now, "Anonymus");
}
else
{
Add(text, LogLevels.Debug, DateTime.Now, userName);
}
}
Upvotes: 3
Views: 2816
Reputation: 10045
Given the facts:
Logger
class which is not unit test friendlyEntries
as public information, nor it could be passed into Logger
as parameterYou have to use Reflection to get Entries
.
var logger = new Logger();
logger.AddDebug("some text", userName: null);
// Get Entries in logger
var entriesField = typeof(Logger).GetField(
"Entries", BindingFlags.NonPublic | BindingFlags.Instance);
var entries = (List<Log>)entriesField.GetValue(logger);
var containsAnonymous = entries.Any(e => e.UserName == "Anonymus");
However, this is usually / arguably not considered as a good practice in unit testing, as this relies on the internals of Logger
class and it is likely that if you change the implementation of Logger
, this unit test can break.
I would still recommend using one of @user8606929's solutions if it is possible.
Upvotes: 0
Reputation: 225
I would recommend that you use a Mocking Framework like Moq. See my attached example code. ILog is the Interface for Log Class.
public interface ILog {
void Add(Log log);
}
Your Logger class could look like this:
public class Logger : ILog{
....
public void Add(Log log)
{
if (!(log.TimeStamp > DateTime.Now))
{
Entries.Add(log);
}
}
}
...
You can design your TestCases like this
using Moq;
public class TestLogger
{
private Mock<ILog> _logMock;
private ILog _logger;
[Setup]
public void SetUp()
{
_logMock = new Mock<ILog>();
_logMock.Setup(a => a.Add(It.IsAny<Log>())).Verifiable(); // check if method is called
_logger = _logMock.Object;
}
...
[Test]
public void SomeTest()
{
//test some business logik - inject your logger instance into businesslogic class
//check if logger was called once
_logMock.Verify(a => a.Add(It.IsAny<Log>()), Times.Once);
}
}
If its not possible to use Moq and external interfaces, you can write your test to check if your Entries List is not empty.
public class Logger
{
public List<Log> Entries = new List<Log>();
...
}
[TestCaseSource(nameof(something))]
public void AddDebugSetAnonymusUserTest()
{
var logger = new Logger();
logger.AddDebug("Text", null);
//here is the check if AddDebug was successful
Assert.AreEqual(1, logger.Entries.Count);
//check if user was anonymous
Assert.AreEqual("Anonymous", logger.Entries.FirstOrDefault().UserName);
}
....
Upvotes: 2