How to stub out the dependency in a static class? - c#

I have a static class wherein I am reading an XML to build a dictionary.
Now this initialization is done in the static constructor.
In order to test this Initialize method, I have to somehow stub out the reading of XML logic and just give it an XDocument for testing, but not sure how can I do that.
internal static class MasterMnemonicsLookup
{
private static Dictionary<string, StateCoverageMnemonic[]> masterMnemonics = new Dictionary<string, StateCoverageMnemonic[]>();
private static StateCoverageMnemonic[] stateCoverageMnemonics;
static MasterMnemonicsLookup()
{
Initialize();
}
private static void Initialize()
{
var resource = XDocument.Parse(GetResourceTextFile("MasterMnemonics.xml"));
var serializer = new XmlSerializer(typeof (MasterMnemonicsType));
var model = (MasterMnemonicsType) serializer.Deserialize(resource.CreateReader());
var stateCoverageMnemonicsList = new List<StateCoverageMnemonic>();
foreach (var masterMnemonic in model.MasterMnemonics)
{
var stateCoverageMnemonicsXml = new List<StateCoverageMnemonic>();
var excludedStates = RiskStates.None;
StateCoverageMnemonic allStateCoverageMnemonic = null;
foreach (var stateCoverageMnemonic in masterMnemonic.StateCoverageMnemonics)
{
var state = stateCoverageMnemonic.StateCode;
if (!state.HasFlag(RiskStates.All))
{
excludedStates = excludedStates | state;
var mnemonic = stateCoverageMnemonic.Mnemonic;
var coverageCode = stateCoverageMnemonic.CoverageCode;
var stateCoverageMnemonicTemp = new StateCoverageMnemonic(state, mnemonic, coverageCode);
stateCoverageMnemonicsXml.Add(stateCoverageMnemonicTemp);
}
else
{
//// TODO: If All occurs twice should we throw an exception
allStateCoverageMnemonic = new StateCoverageMnemonic(state, stateCoverageMnemonic.Mnemonic, stateCoverageMnemonic.CoverageCode);
}
}
if (allStateCoverageMnemonic != null)
{
stateCoverageMnemonicsXml.Add(new StateCoverageMnemonic(RiskStates.All ^ excludedStates, allStateCoverageMnemonic.Mnemonic, allStateCoverageMnemonic.CoverageCode));
}
stateCoverageMnemonicsList.AddRange(stateCoverageMnemonicsXml);
masterMnemonics.Add(masterMnemonic.MasterMnemonic, stateCoverageMnemonicsXml.ToArray());
}
stateCoverageMnemonics = stateCoverageMnemonicsList.ToArray();
}
private static string GetResourceTextFile(string filename)
{
string result = string.Empty;
using (Stream stream = typeof(MasterMnemonicsLookup).Assembly.GetManifestResourceStream("Geico.Applications.Business.CoverageApi.DomainLayer.DataLayer." + filename))
{
var streamReader = new StreamReader(stream);
result = streamReader.ReadToEnd();
}
return result;
}
}

Using static contructors in this way is not advised, and your scenario is a good example why. You might try the singleton pattern using a public instance constructor that accepts an XDocument. (You can use internal, but this makes it harder to unit test). This is a simple form of dependency injection.
For testing, an instance of your class can simply be created by your testing framework with the test XDocument.
For your live application, a static instance of your class can be initialized and held by a container type, and the appropriate XDocument can be passed in privately (within the container).

I agree with Darious Vaughan-Scott
But if you want to keep using the static constructor you may want to put the loading logic into a seperate class which makes it easier to test.
For example
internal class MasterMnemonicsLoader
{
public void Load(
XDocument resource,
Dictionary<string, StateCoverageMnemonic[]> masterMnemonics,
StateCoverageMnemonic[] stateCoverageMnemonics)
{
//Do the loading here
}
}
and in the Initialize method you can call the Load method
private static void Initialize()
{
var resource = XDocument.Parse(GetResourceTextFile("MasterMnemonics.xml"));
var loader = MasterMnemonicsLoader();
loader.Load(resource, masterMnemonics, stateCoverageMnemonics);

Related

How can the FileInfo class be mocked using System.IO.Abstractions?

I have injected the System.IO.Abstractions.IFileSystem interface into a class so that I can unit test file system interactions. There is one place in the class that uses new FileInfo(fileName). What is the replacement for that when using the IFileSystem interface and MockFileSystem?
Replacing File.OpenRead with _fileSystem.File.OpenRead is simple...
public string? Decrypt(string encryptedFilePath, string privateKeyArmor, string passPhrase)
{
try
{
using var privateKeyStream = new MemoryStream(Encoding.ASCII.GetBytes(privateKeyArmor));
using var encryptedFileStream = _fileSystem.File.OpenRead(encryptedFilePath);
var inputStream = PgpUtilities.GetDecoderStream(encryptedFileStream);
...
...but I don't know how to replace new FileInfo(fileName) here.
private byte[] CompressFile(string fileName, CompressionAlgorithmTag algorithm)
{
var outputStream = new MemoryStream();
var compressedDataGen = new PgpCompressedDataGenerator(algorithm);
PgpUtilities.WriteFileToLiteralData(compressedDataGen.Open(outputStream), PgpLiteralData.Binary,
new FileInfo(fileName));
...
I tried _fileSystem.FileInfo.FromFileName(fileName), but that returns IFileInfo instead of FileInfo and the WriteFileToLiteralData method won't take that.
There is a helper function FileInfo.New(string fileName) which can be used to create/use a mock IFileInfo object
public class FileInfoTest
{
private readonly IFileSystem _fileSystem;
public FileInfoTest()
: this (new FileSystem())
{
}
internal FileInfoTest(IFileSystem fileSystem)
{
_fileSystem = fileSystem;
}
public bool GetIsReadOnly(string path)
{
var info = _fileSystem.FileInfo.New(path);
return info.IsReadOnly;
}
}
To demonstrate this I have a physical file which is not read-only.
The first test, returns the IsReadonly state of the physical file.
The second, returns a mocked IFileInfo object with IsReadOnly set to true.
[TestMethod]
public void CheckFileInfoAgainstPhysicalFile()
{
var tester = new FileInfoTest();
var isReadOnly = tester.GetIsReadOnly(#"c:\dev\File.txt");
Assert.IsFalse(isReadOnly);
}
[TestMethod]
public void CheckFileInfoAgainstMock()
{
var mockFileInfo = new Mock<IFileInfo>();
mockFileInfo.SetupGet(mk => mk.IsReadOnly).Returns(true);
var mockFileSystem = new Mock<IFileSystem>();
mockFileSystem.Setup(mk => mk.FileInfo.New(#"c:\dev\File.txt")).Returns(mockFileInfo.Object);
var tester = new FileInfoTest(mockFileSystem.Object);
var isReadOnly = tester.GetIsReadOnly(#"c:\dev\File.txt");
Assert.IsTrue(isReadOnly);
}
As mentioned in the comment, the above doesn't address the basic problem - PgpUtilities doesn't know what an IFileInfo is.
There is a way to fix this but it may not be worth the effort.
Define an interface for the methods used from the static class.
Inject this interface.
In the default implementation of `IPgpUtilities`, use reflection to get at the `FileInfo` instance inside the `FileInfoWrapper` and pass it through to the external routine.
// Stand-in for External utility (returns a string so we can see it
// doing something with the original file)
public static class PgpUtilitiesOriginal
{
public static string WriteFileToLiteralData(Stream outputStream,
char fileType,
FileInfo file)
{
return file.Name;
}
}
// Interface for injection
public interface IPgpUtilties
{
string WriteFileToLiteralData(Stream outputStream,
char fileType,
IFileInfo file);
}
// Wrapper for the External Utility
public class DefaultPgpUtilities : IPgpUtilties
{
public string WriteFileToLiteralData(Stream outputStream, char fileType, IFileInfo file)
{
var instanceInfo = file.GetType().GetField("instance", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
var instance = (FileInfo)instanceInfo.GetValue(file);
return PgpUtilitiesOriginal.WriteFileToLiteralData(outputStream, fileType, instance);
}
}
// Test Target
public class Tester
{
private readonly IFileSystem _fileSystem;
private readonly IPgpUtilties _pgpUtilities;
public Tester()
: this(new FileSystem(), new DefaultPgpUtilities())
{
}
public Tester(IFileSystem fileSystem, IPgpUtilties pgpUtilities)
{
_fileSystem = fileSystem;
_pgpUtilities = pgpUtilities;
}
public string Run(string fileName)
{
return _pgpUtilities.WriteFileToLiteralData(null, '\0', _fileSystem.FileInfo.FromFileName(fileName));
}
}
[TestMethod]
public void PhysicalFile()
{
var tester = new Tester();
var ret = tester.Run(#"c:\dev\file.txt");
Assert.AreEqual("file.txt", ret);
}
[TestMethod]
public void MockedFile()
{
var mockFileObject = new Mock<IFileInfo>();
var mockFileSystem = new Mock<IFileSystem>();
mockFileSystem.Setup(mk => mk.FileInfo.FromFileName(#"c:\dev\file.txt")).Returns(mockFileObject.Object);
var mockPgpUtilties = new Mock<IPgpUtilties>();
mockPgpUtilties.Setup(mk => mk.WriteFileToLiteralData(It.IsAny<Stream>(), It.IsAny<char>(), mockFileObject.Object)).Returns("Hello World");
var tester = new Tester(mockFileSystem.Object, mockPgpUtilties.Object);
var ret= tester.Run(#"c:\dev\file.txt");
Assert.AreEqual("Hello World", ret);
}
Again, sorry about the piss-poor reading of the original question on my part.

N Unit Test Debugger not stepping inside a static method

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.

Need to execute helper methods only once (cache results)

I am creating a helper class for my MVC application. This class will contain static methods that will pull information the first time the user logs into the system.
I have created two methods that will return lists like list of countries and list of languages. I don't want to execute this every time but save results of first call and return it for subsequent calls.
public static List<Languages> GetLanguages()
{
using (var db = new MCREntities())
{
var languages = db.spGetLanguages(0);
return Mapper.Map<List<Languages>>(languages);
}
}
public static List<Countries> GetCountries()
{
using (var db = new MCREntities())
{
var countries = db.spGetAllCountries("");
return Mapper.Map<List<Countries>>(countries);
}
}
Inside your class you can have static list which would hold Languages anly first time would try to access database.
private static List<Languages> _languages = null;
public static List<Languages> GetLanguages()
{
if(_languages == null){
using (var db = new MCREntities())
{
var languages = db.spGetLanguages(0);
_languages = Mapper.Map<List<Languages>>(languages);
}
}
return _languages;
}
Alternatively, you can implement cache
i would say create a class with the required properties liek
public static class CurrentSession{
List<Languages> lang{get;set;}
List<Countries> countries{get;set;}
}
and in global.asax file
protected void Application_Start()
{
//.........predefined codes
CurrentSession.lang = GetLanguages();
CurrentSession.Countries =GetCountries();

Disposing TestCaseSource elements in NUnit test

I am using TestCaseSource with NUnit. The below code generates IEnumerable of TestCaseData that represent an archive entry, which is an input for a test.
private class GithubRepositoryTestCasesFactory
{
private const string GithubRepositoryZip = "https://github.com/QualiSystems/tosca/archive/master.zip";
public static IEnumerable TestCases
{
get
{
using (var tempFile = new TempFile(Path.GetTempPath()))
using (var client = new WebClient())
{
client.DownloadFile(GithubRepositoryZip, tempFile.FilePath);
using (var zipToOpen = new FileStream(tempFile.FilePath, FileMode.Open))
using (var archive = new ZipArchive(zipToOpen, ZipArchiveMode.Read))
{
foreach (var archiveEntry in archive.Entries.Where(a =>
Path.GetExtension(a.Name).EqualsAny(".yaml", ".yml")))
{
yield return new TestCaseData(archiveEntry);
}
}
}
}
}
}
[Test, TestCaseSource(typeof (GithubRepositoryTestCasesFactory), "TestCases")]
public void Validate_Tosca_Files_In_Github_Repository_Of_Quali(ZipArchiveEntry zipArchiveEntry)
{
var toscaNetAnalyzer = new ToscaNetAnalyzer();
toscaNetAnalyzer.Analyze(new StreamReader(zipArchiveEntry.Open()));
}
The above code fails on the following line:
zipArchiveEntry.Open()
with an exception:
System.ObjectDisposedException "Cannot access a disposed object.
Object name: 'ZipArchive'."
Is there any way to control the disposing of objects created for test data case?
The problem is that the ZipArchive and its children are being disposed of at the end of the using block.
Try rigging up something like this within your fixture fixture:
// MyDisposable an IDisposable with child elements
private static MyDisposable _parent;
// This will be run once when the fixture is finished running
[OneTimeTearDown]
public void Teardown()
{
if (_parent != null)
{
_parent.Dispose();
_parent = null;
}
}
// This will be run once per test which uses it, prior to running the test
private static IEnumerable<TestCaseData> GetTestCases()
{
// Create your data without a 'using' statement and store in a static member
_parent = new MyDisposable(true);
return _parent.Children.Select(md => new TestCaseData(md));
}
// This method will be run once per test case in the return value of 'GetTestCases'
[TestCaseSource("GetTestCases")]
public void TestSafe(MyDisposable myDisposable)
{
Assert.IsFalse(myDisposable.HasChildren);
}
The key is to set the static member when creating the test case data, then disposing of it on the fixture tear down.

Deserialize object to itself

I have found some threads about this problem, like this and this but I cannot figure out how I could implement this for my code.
I have something like this:
public sealed class Party
{
public Party()
{
load();
}
....
public async void Load()
{
string fileName = this.Name + ".xml";
var files = ApplicationData.Current.LocalFolder.GetFilesAsync(Windows.Storage.Search.CommonFileQuery.OrderByName).GetResults();
var file = files.FirstOrDefault(f => f.Name == fileName);
if (file != null)
{
using (var stream = await ApplicationData.Current.LocalFolder.OpenStreamForReadAsync(fileName))
{
XmlSerializer serializer = new XmlSerializer(typeof(Party));
Party data = (Party)serializer.Deserialize(stream);
this = data;
}
}
}
}
This throws me the "cannot assign to ' this ' because it is read-only". Since I read a file and I need to await it, it have to be async, and then I cannot have the class as a return type.
Any ideas for how to deserialize this to itself?
You can't assign to this. It's an instance of an object, and it makes no sense to change it.
Either have a static method that returns the Party (and use that to create the class):
public static Party Load()
{
// ... Deserialize
return (Party)serializer.Deserialize(stream);
}
Or load the information into your class using the deserialized object (which would be inefficient, since they're the same type):
public void Load()
{
// ... Deserialize
Party data = (Party)serializer.Deserialize(stream);
this.Name = data.Name;
this.PartyInfo = data.PartyInfo;
}
Clearly, the static method should be preferred here, and is considered the factory pattern.

Categories

Resources