N Unit Test Debugger not stepping inside a static method - c#

My unit testing method is as follows
[Test]
public void TrackPublicationChangesOnCDSTest()
{
//Arrange
// objDiskDeliveryBO = new DiskDeliveryBO();
//Act
var actualResult = objDiskDeliveryBO.TrackPublicationChangesOnCDS();
//Assert
var expectedZipName = 0;
Assert.AreEqual(expectedZipName, actualResult);
}
The Actual method TrackPublicationChangesOnCDS in BO is as follows
public int TrackPublicationChangesOnCDS()
{
var resultFlag = -1;
try
{
string pubUpdateFileCDSPath = CommonCalls.PubUpdateFileCDSPath;
string pubUpdateFileLocalPath = CommonCalls.PubUpdateFileLocalPath;
if (File.Exists(pubUpdateFileCDSPath))
File.Copy(pubUpdateFileCDSPath, pubUpdateFileLocalPath, true);
if (File.Exists(pubUpdateFileLocalPath))
{
string[] pubRecords = File.ReadAllLines(pubUpdateFileLocalPath);
var pubRecordsExceptToday = pubRecords.Where(p => !p.Trim().EndsWith(DateTime.Now.ToString("dd/MM/yy"))).ToList();
resultFlag = new DiskDeliveryDAO().TrackPublicationChangesOnCDS(pubRecordsExceptToday);
File.WriteAllText(pubUpdateFileLocalPath, string.Empty);
string[] pubRecordsCDS = File.ReadAllLines(pubUpdateFileCDSPath);
var pubRecordsTodayCDS = pubRecordsCDS.Where(p => p.Trim().EndsWith(DateTime.Now.ToString("dd/MM/yy"))).ToList();
File.WriteAllLines(pubUpdateFileCDSPath, pubRecordsTodayCDS);
}
return resultFlag;
}
catch (Exception)
{
return -1;
}
}
While debugging Debugger comes till
string pubUpdateFileCDSPath = CommonCalls.PubUpdateFileCDSPath;
But CommonCalls.PubUpdateFileCDSPath; return empty string . It should return a file path . when the method is called directly it works fine . It doesn't work when it is called inside a unit testing method.
CommonCalls.PubUpdateFileCDSPath is a static property defined as below .
public static string PubUpdateFileCDSPath
{
get { return GetXmlConfigValue("PubUpdateFileCDSPath"); }
}
public static string GetXmlConfigValue(string nodeName)
{
var xml = new XmlDocument();
xml.Load(ConfigValuesXml);
var node = xml.SelectSingleNode("JanesOfflineDeliveryService/" + nodeName);
return node != null ? node.InnerText : string.Empty;
}
Configvaluesxml is a xml file path . Contents of the file is
<JanesOfflineDeliveryService>
<PubUpdateFileCDSPath>D:\OfflineDelivery\CDS\pub_update.txt</PubUpdateFileCDSPath>
<PubUpdateFileLocalPath>D:\pub_update.txt</PubUpdateFileLocalPath>
</JanesOfflineDeliveryService>

In your test scenario GetXmlConfigValue("PubUpdateFileCDSPath") does not exist, so string empty is returned. Thats why you should avoid static methods, because they are not mockable. A workaround could be to pass the path variables into the method.

Using static dependencies make unit testing code in isolation difficult. invert the dependency by abstracting and injecting them into the dependent class.
public interface ICommonCalls {
string PubUpdateFileCDSPath { get; }
string PubUpdateFileLocalPath { get; }
}
the implementation of the above interface would either wrap the your static calls or better yet just implement them.
The dependent class would be refactored to allow for the dependency inversion.
public class DiskDeliveryBO {
private readonly ICommonCalls CommonCalls;
public DiskDeliveryBO(ICommonCalls common) {
this.CommonCalls = common;
}
//...other code removed for brevity.
}
However the target method also has a lot of tight coupling to implementation concerns like the file system. That too should be abstracted and inverted out of the dependent class.

Related

Unit test method which deletes the files from a folder

we have a method which takes the folder name and number of days as a parameter.
public void Delete(string folder, int days)
{
var files = Directory.GetFiles(folder);
foreach (var file in files)
{
var fi = new FileInfo(file);
var fiCreationTime = fi.CreationTime;
var deleteOlderThan= DateTime.Now.AddDays(-days);
if (fiCreationTime >= deleteOlderThan) continue;
fi.Delete();
}
}
What is the best way to unit test such methods in c#
Actually you cannot unit test your method, because it depends on external APIs (FileSystem, DateTime).
So what you should do is separate logic and integration with external sources, it might look like this:
public class MyFileInfo
{
public string FileName { get; set; }
public DateTime CreationTime { get; set; }
}
public interface IDateTimeProvider
{
DateTime GetCurrentTime();
}
public interface IMyFileSystemService
{
IEnumerable<MyFileInfo> GetFileInfos(string folder);
void DeleteFile(MyFileInfo myFileInfo);
}
public class MyService
{
private readonly IMyFileSystemService _myFileSystemService;
private readonly IDateTimeProvider _dateTimeProvider;
public MyService(IMyFileSystemService myFileSystemService, IDateTimeProvider dateTimeProvider)
{
_myFileSystemService = myFileSystemService;
_dateTimeProvider = dateTimeProvider;
}
public void Delete(string folder, int days)
{
var files = _myFileSystemService.GetFileInfos(folder);
foreach (var file in files)
{
var deleteOlderThan = _dateTimeProvider.GetCurrentTime().AddDays(-days);
if (file.CreationTime >= deleteOlderThan) continue;
_myFileSystemService.DeleteFile(file);
}
}
}
I think implementation of interfaces IDateTimeProvider and IMyFileSystemService should not be an issue.
Now you can write clean unit tests for MyService.Delete
If you want to unit test the method you have shown it would be difficult in the way it is currently written, but we could mock the File class and pass an interface for it to use:
public class FileDeleter
{
private readonly IFileOperator _fileOperator;
public FileDeleter(IFileOperator fileOperator)
{
_fileOperator= fileOperator
}
public void Delete(string folder, int days)
{
var files = _fileClass.GetFiles(folder);
foreach (var file in files)
{
var fi = _fileClass.GetFileInfo(file);
var fiCreationTime = fi.CreationTime;
var deleteOlderThan= DateTime.Now.AddDays(-days);
if (fiCreationTime >= deleteOlderThan)
continue;
fi.Delete();
}
}
}
public interface IFileClass
{
IEnumerable<string> GetFiles(string path);
IFileInfo GetFileInfo(string filePath);
}
public interface IFileInfo
{
DateTime CreationTime { get; }
void Delete();
}
After that, simply mock the two classes with a library like: https://github.com/Moq/moq4/wiki/Quickstart
and write your unit tests testing whatever logic is required.
EDIT: As others have pointed out, datetime.now might be a good thing to mock too, but can be done in that same way.
Another possibility is to use static helper classes
public static class FileEx
{
public static Func<string, IEnumerable<string>> EnumerateFiles { set; get; }
= Directory.EnumerateFiles;
}
and then only use the helper classes:
var files = FileEx.EnumerateFiles(...);
This way you can change the method in your unit tests.
[Test]
public void Test()
{
FileEx.EnumerateFiles = (_) => new [] { "file1", "file2" };
// your test here
// Reset the method:
FileEx.EnumerateFiles = Directory.EnumerateFiles;
}
This works for most static helper methods and is way easier refactoring every class so it can be injected.
Downsides
you will lose function overloading.
will only work for static classes (in your example it won't work for FileInfo).
Upsides
really easy
easy to implement
easy to change while testing
easy to use
Update to remarks in the comments:
It is viable to replace system methods as Directory.EnumerateFiles in your unit tests.
Because you are testing your Delete method and one can assume that Microsoft has tested the framework code. Therefore the only thing the unit test must prove is that the Delete method has to correct output and side effects.
The 100% solution is that lot of this has to be injected in because it either has sideeffects or is non-determenistic:
1) Directory.GetFiles
2) new FileInfo(file)
3) fi.CreationTime
4) DateTime.Now.AddDays
5) fi.Delete
So you inject e.g. a datetimeservice in that in production that returns datetime, and in test where it always returns some fixed date. And use a mocking framework to check that sometimes the delete method is called, and other times it isn't called.
The perfect solution for your code would create an interface which has methods for all files operation and then mock those methods
but you can also create virtual methods for those file operation in your sample class and mock that method in a unit test
Following is code implementation of your actual code
public class Sample
{
public void Delete(string folder, int days)
{
var files = GetFiles(folder);
foreach (var file in files)
{
var fi = GetFileInfo(file);
var fiCreationTime = fi.CreationTime;
var deleteOlderThan = DateTime.Now.AddDays(-days);
if (fiCreationTime >= deleteOlderThan) continue;
DeleteFile(fi);
}
}
public virtual void DeleteFile(FileInfo f)
{
f.Delete();
}
public virtual string[] GetFiles(string path)
{
return Directory.GetFiles(path);
}
public virtual FileInfo GetFileInfo(string file)
{
return new FileInfo(file);
}
}
And following is your unit test class
public class NUnitTest
{
[TestFixture]
public class UnitTest1
{
private Mock<Sample> _sample;
private FileInfo _fileInfo;
[SetUp]
public void Setup()
{
_sample = new Mock<Sample>();
}
[Test]
public void File_Should_Not_Delete()
{
_fileInfo = new FileInfo("file");
_fileInfo.Create();
_sample.Setup(x => x.GetFiles(It.IsAny<string>())).Returns(() => new[] {"file1"});
_sample.Setup(x => x.GetFileInfo(It.IsAny<string>())).Returns(() => _fileInfo);
_sample.Setup(x => x.DeleteFile(It.IsAny<FileInfo>())).Verifiable();
_sample.Object.Delete("file1",2);
_sample.Verify(x => x.DeleteFile(It.IsAny<FileInfo>()), Times.Never);
}
[Test]
public void File_Should_Delete()
{
_fileInfo = new FileInfo("file1");
_fileInfo.Create();
_sample.Setup(x => x.GetFiles(It.IsAny<string>())).Returns(() => new[] { "file1" });
_sample.Setup(x => x.GetFileInfo(It.IsAny<string>())).Returns(() => _fileInfo);
_sample.Setup(x => x.DeleteFile(It.IsAny<FileInfo>())).Verifiable();
_sample.Object.Delete("file1", -2);
_sample.Verify(x => x.DeleteFile(It.IsAny<FileInfo>()), Times.Once);
}
}
}
I know this is not good design practice but I just want to showcase you a different way of doing unit testing using a virtual method.
Bestway is to create an interface and mock those interface method which I created as a virtual

unit test on a static function that read a file

I have the followed function and trying to add Unit Test on a old project. I'm a beginner in Unit Test so forgive me if the question is stupid ...
public static string GetDefaultName(bool isResponsive)
{
//Read web.config file
Configuration configuration = WebConfigurationManager.OpenWebConfiguration(System.Web.HttpContext.Current.Request.ApplicationPath);
if (!isResponsive)
{
if (configuration.AppSettings.Settings.AllKeys.Contains("defaultTheme"))
{
return configuration.AppSettings.Settings["defaultTheme"].Value;
}
else
return "default";
}
else
{
// ...
}
}
And I'm trying to write an Unit Test in this way :
[TestMethod]
public void ReturnDefaulThemeNametIfThemeIsResponsive()
{
var theme = new Theme {isResponsive = true};
var defaultName = Themes.GetDefaultName(theme.isResponsive);
Assert.AreEqual(defaultName, "defaultThemeResponsive");
}
I wonder what is the best way to test this static function, and how to mock the part who read the web.config file ?
I try to stay away from static utilities that have dependencies as they are difficult to unit test. But in this case it is possible. You will have to do some refactoring.
First you need to abstract all calls to access configuration.
public interface IThemeSettings {
bool Contains(string key);
string this[string key] { get; }
}
You can then update the static Themes utility class to use this abstraction as a dependency
public static class Themes {
private static IThemeSettings themes;
public static void Configure(Func<IThemeSettings> factory) {
if (factory == null) throw new InvalidOperationException("Must provide a valid factory method");
themes = factory();
}
public static string GetDefaultName(bool isResponsive) {
if (themes == null) throw new InvalidOperationException("Themes has not been configured.");
string result = string.Empty;
if (!isResponsive) {
if (themes.Contains("defaultTheme")) {
result = themes["defaultTheme"];
} else
result = "default";
} else {
// ...
}
return result;
}
//...
}
That wat you can now configure the utility to use mocks when testing
[TestMethod]
public void ReturnDefaulThemeNametIfThemeIsResponsive() {
//Arrange
var key = "defaultTheme";
var expected = "defaultThemeResponsive";
var mockSettings = new Mock<IThemeSettings>();
mockSettings.Setup(m => m.Contains(key)).Returns(true);
mockSettings.Setup(m => m[key]).Returns(expected);
//In production you would also do something like this with
//the actual production implementation, not a mock
Themes.Configure(() => mockSettings.Object);
var theme = new Theme { isResponsive = true };
//Act
var defaultName = Themes.GetDefaultName(theme.isResponsive);
//Assert
Assert.AreEqual(expected, defaultName);
}
In this case I used Moq as the mocking framework.
Some advice. Try not to have your classes tightly coupled to HttpContext. Your classes should depend on abstractions and not on concretions.
The way your method is designed at the moment does not allow you to mock the part that reads the config file. If you want to be able to do that you need to make it a parameter to your method. One way to make that easier is to define an interface like
public interface ISetting
{
string GetConfigItem(string itemName);
}
Then wrap the Configuration object in a settings manager class that implements this.
public class MySettings:ISetting
{
public string GetConfigItem(string ItemName)
{
// return value of the setting. In your case code that gets value of "defaultTheme"
}
}
Your method will now have a dependency on ISetting.
For testing purposes you can create a mock that implements the interface and will return what ever value you want independent of the current state and content of the web.config
public class SettingsTestHelper:ISetting
{
private _valueToReturn;
public SettingsTestHelper(string valueToReturn)
{
_valueToReturn=valueToReturn;
}
public string GetConfigItem(string itemName)
{
return valueToReturn;
}
}
With this you can now create a unit test(doesn't compile, but you'll get the idea)
[TestMethod]
public void CanGetSetting()
{
var helper = new SettingsTestHelper("default");
var result = ClasThatImplementsYourStaticMethod.GetDefaultName(helper, true);
Assert.AreEqual(expected, actual);
}

Error when setting up a mock config reader

I'm trying to learn Moq by writing some simple unit tests. Some of them have to do with a class called AppSettingsReader:
public class BackgroundCheckServiceAppSettingsReader : IBackgroundCheckServiceAppSettingsReader
{
private string _someAppSetting;
public BackgroundCheckServiceAppSettingsReader(IWorkHandlerConfigReader configReader)
{
if (configReader.AppSettingsSection.Settings["SomeAppSetting"] != null)
this._someAppSetting = configReader.AppSettingsSection.Settings["SomeAppSetting"].Value;
}
public string SomeAppSetting
{
get { return _someAppSetting; }
}
}
The interface for the class is defined like this:
public interface IBackgroundCheckServiceAppSettingsReader
{
string SomeAppSetting { get; }
}
And the IWorkHandlerConfigReader (which I do not have permission to modify) is defined like so:
public interface IWorkHandlerConfigReader
{
AppSettingsSection AppSettingsSection { get; }
ConnectionStringsSection ConnectionStringsSection { get; }
ConfigurationSectionCollection Sections { get; }
ConfigurationSection GetSection(string sectionName);
}
When I write the unit test, I create a Mock of the IWorkHandlerConfigReader and try to set up the expected behavior:
//Arrange
string expectedReturnValue = "This_is_from_the_app_settings";
var configReaderMock = new Mock<IWorkHandlerConfigReader>();
configReaderMock.Setup(cr => cr.AppSettingsSection.Settings["SomeAppSetting"].Value).Returns(expectedReturnValue);
//Act
var reader = new BackgroundCheckServiceAppSettingsReader(configReaderMock.Object);
var result = reader.SomeAppSetting;
//Assert
Assert.Equal(expectedReturnValue, result);
This compiles, but when I run the test, I see the following error: System.NotSupportedException : Invalid setup on a non-virtual (overridable in VB) member: cr => cr.AppSettingsSection.Settings["SomeAppSetting"].Value
Is there another way to approach this other than a Mock object? Am I misunderstanding how it should be used?
You are actually asking dependency for AppSettingsSection instance. So, you should setup this property getter to return some section instance with data you need:
// Arrange
string expectedReturnValue = "This_is_from_the_app_settings";
var appSettings = new AppSettingsSection();
appSettings.Settings.Add("SomeAppSetting", expectedReturnValue);
var configReaderMock = new Mock<IWorkHandlerConfigReader>();
configReaderMock.Setup(cr => cr.AppSettingsSection).Returns(appSettings);
var reader = new BackgroundCheckServiceAppSettingsReader(configReaderMock.Object);
// Act
var result = reader.SomeAppSetting;
// Assert
Assert.Equal(expectedReturnValue, result);

How write stub method with NUnit in C#

I have 2 classes:
FirstDeep.cs
SecondDeep.cs
I did simple code for example:
class FirstDeep
{
public FirstDeep() { }
public string AddA(string str)
{
SecondDeep sd = new SecondDeep();
bool flag = sd.SomethingToDo(str);
if (flag == true)
str = string.Concat(str, "AAA");
else
str = string.Concat(str, "BBB");
return str;
}
}
and
class SecondDeep
{
public bool SomethingToDo(string str)
{
bool flag = false;
if (str.Length < 10)
{
//todo something in DB, and after that flag should be TRUE
}
return flag;
}
}
Then I want to write unit test for method "AddA":
class Tests
{
[Test]
public void AddATest()
{
string expected = "ABCAAA";
FirstDeep fd = new FirstDeep();
string res = fd.AddA("ABC");
Assert.AreEqual(expected, res);
}
}
And after that I have trouble, I don't know how correct write stub for method SomethingToDo in my Test class. I always have false. I should just return TRUE. But how?
A good way to allow you to write stubs is to use dependency injection. FirstDeep depends on SecondDeep and in your test you want to replace SecondDeep with a stub.
First change your existing code by extracting an interface for SecondDeep and then inject that into FirstDeep in the constructor:
interface ISecondDeep {
Boolean SomethingToDo(String str);
}
class SecondDeep : ISecondDeep { ... }
class FirstDeep {
readonly ISecondDeep secondDeep;
public FirstDeep(ISecondDeep secondDeep) {
this.secondDeep = secondDeep;
}
public String AddA(String str) {
var flag = this.secondDeep.SomethingToDo(str);
...
}
}
Note that FirstDeep no longer creates a SecondDeep instance. Instead an instance is injected in the constructor.
In your test you can create a stub for ISecondDeep where SomethingToDo always returns true:
class SecondDeepStub : ISecondDeep {
public Boolean SomethingToDo(String str) {
return true;
}
}
In the test you use the stub:
var firstDeep = new FirstDeep(new SecondDeepStub());
In production code you use the "real" SecondDeep:
var firstDeep = new FirstDeep(new SecondDeep());
Using a dependency injection container and a stubbing framework can make a lot of this easier to do.
If you don't want to rewrite your code you can use a framework for intercepting calls like Microsoft Moles. In the next version of Visual Studio a similar technology will be available in the Fakes Framework.
To make your code testable, do not instantiate dependencies inside your class. Use dependency injection (via constructor, property or parameter). Also use abstract classes or interfaces to allow mocking of dependencies:
class FirstDeep
{
private ISecondDeep oa;
public FirstDeep(ISecondDeep oa)
{
this.oa = oa;
}
public string AddA(string str)
{
return String.Concat(str, oa.SomethingToDo(str) ? "AAA" : "BBB");
}
}
Depending on abstractions allows you to test your class in isolation.
interface ISecondDeep
{
bool SomethingToDo(string str);
}
class SecondDeep : ISecondDeep
{
public bool SomethingToDo(string str)
{
bool flag = false;
if (str.Length < 10)
{
// without abstraction your test will require database
}
return flag;
}
}
Here is test sample (using Moq). It shows you how you can return true from call to your mocked dependency:
[TestFixture]
class Tests
{
[Test]
public void AddAAATest()
{
// Arrange
Mock<ISecondDeep> secondDeep = new Mock<ISecondDeep>();
secondDeep.Setup(x => x.SomethingToDo(It.IsAny<string>())).Returns(true);
// Act
FirstDeep fd = new FirstDeep(secondDeep.Object);
// Assert
Assert.That(fd.AddA("ABD"), Is.EqualTo("ABCAAA"));
}
}

Unit-testing an action which calls session object

How can I unit test a method which uses a session object inside of its body?
Let us say I have the following action:
[HttpPost]
public JsonResult GetSearchResultGrid(JqGridParams gridParams, Guid campaignId, string queryItemsString)
{
var queryItems = new JavaScriptSerializer().Deserialize<IList<FilledQueryItem>>(queryItemsString);
IPageData pageData = gridParams.ToPageData();
var extraFieldLinker = SessionHandler.CurrentExtraFieldsLinker;
var searchParams = new SearchParamsModel(extraFieldLinker, queryItems);
IList<CustomerSearchResultRow> searchResults = null;
searchResults = _customerService.SearchCustomersByUrlAndCampaign(campaignId,
searchParams.SearchString,
searchParams.AddressFilterPredicate,
pageData);
return GetGridData<CustomerSearchResultGridDefinition, CustomerSearchResultRow>(searchResults, pageData);
}
I made the following unit tests which fails so far because of the session thing:
[Test]
public void CanGetSearchResultGrid()
{
//Initialize
var mockJqGridParams = new Mock<JqGridParams>();
var mockPageData = new Mock<IPageData>();
IPagedList<CustomerSearchResultRow> mockPagedResult = new PagedList<CustomerSearchResultRow>(mockPageData.Object);
var guid= Guid.NewGuid();
const string searchString =
"[{\"Caption\":\"FirstName\",\"ConditionType\":\"contains\",\"Value\":\"d\",\"NextItem\":\"Last\"}]";
Func<Address,bool> addressFilterPredicate = (x => true);
//Setup
mockJqGridParams.Setup(x => x.ToPageData()).Returns(mockPageData.Object);
_customerService.Setup(x => x.SearchCustomersByUrlAndCampaign(guid, searchString, addressFilterPredicate, mockPageData.Object))
.Returns(mockPagedResult);
//Call
var result = _homeController.GetSearchResultGrid(mockJqGridParams.Object, guid, searchString);
mockJqGridParams.Verify(x => x.ToPageData(), Times.Once());
_customerService.Verify(x => x.SearchCustomersByUrlAndCampaign(guid, searchString, addressFilterPredicate, mockPageData.Object)
, Times.Once());
//Verify
Assert.That(result, Is.Not.Null);
Assert.That(result, Is.TypeOf(typeof(JsonResult)));
}
And the method from the helper of course:
public static ExtraFieldsLinker CurrentExtraFieldsLinker
{
get
{
object extraFieldLinker = GetSessionObject(EXTRA_FIELDS_LINKER);
return extraFieldLinker as ExtraFieldsLinker;
}
set { SetSessionObject(EXTRA_FIELDS_LINKER, value); }
}
I've solved similar issues (use of static data accessors that aren't mock friendly - in particular, HttpContext.Current) by wrapping the access in another object, and accessing it through an interface. You could do something like:
pubic interface ISessionData
{
ExtraFieldsLinker CurrentExtraFieldsLinker { get; set; }
}
public class SessionDataImpl : ISessionData
{
ExtraFieldsLinker CurrentExtraFieldsLinker
{
// Note: this code is somewhat bogus,
// since I think these are methods of your class.
// But it illustrates the point. You'd put all the access here
get { return (ExtraFieldsLinker)GetSessionObject(EXTRA_FIELDS_LINKER); }
set { SetSessionObject(EXTRA_FIELDS_LINKER, value); }
}
}
public class ClassThatContainsYourAction
{
static ClassThatContainsYourAction()
{
SessionData = new SessionDataImpl();
}
public static ISessionData SessionData { get; private set; }
// Making this access very ugly so you don't do it by accident
public void SetSessionDataForUnitTests(ISessionData sessionData)
{
SessionData = sessionData;
}
[HttpPost]
public JsonResult GetSearchResultGrid(JqGridParams gridParams,
Guid campaignId, string queryItemsString)
{
var queryItems = // ...
IPageData pageData = // ...
// Access your shared state only through SessionData
var extraFieldLinker = SessionData.CurrentExtraFieldsLinker;
// ...
}
}
Then your unit test can set the ISessionData instance to a mock object before calling GetSearchResultGrid.
Ideally you'd use a Dependency Injection library at some point, and get rid of the static constructor.
If you can figure out a way to make your ISessionData an instanced object instead of static, even better. Mock object frameworks tend to like to create a new mock type for every test case, and having mocks lying around from previous tests is kind of gross. I believe session state is going to be global to your session anyway, so you might not have to do anything tricky to make a non-static object work.

Categories

Resources