Mocking xml file for unit testing with Rhinomocks - c#

I want to mock xml used as below for unit tests.I am using Rhinomocks framework for mocking.How can I unit test my methods by not using the actual xml file.Do I have to change my code structure.
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class MyService : IMyService
{
private readonly string mSchemaPath = Path.Combine(HostingEnvironment.ApplicationPhysicalPath, "App_Data",
"schema_0.1.xsd");
private readonly string mXmlPath = Path.Combine(HostingEnvironment.ApplicationPhysicalPath, "App_Data",
"MyDataRecords.xml");
private XDocument mXDocument;
public MyService()
{
try
{
//load xml document
mXDocument = XDocument.Load(mXmlPath);
if (mXDocument == null)
{
throw new Exception("Null returned while reading xml file");
}
}
catch (Exception e)
{
//my exception management code
}
}
public List<MyDataRecords> GetAllRecords()
{
////fetch records from xDocument
mXDocument.Save();
}
public void AddRecord(MyRecord record)
{
////add record
mXDocument.Save();
}

UPDATED:
I've modified your MyService class to have an overloaded constructor, which accepts Func<string, XDocument> to load an XDocument, and also Func<string> to resolve the value that corresponds to HostingEnvironment.ApplicationPhysicalPath . When the default constructor is called, the same call to XDocument.Load is performed, and likewise for using HostingEnvironment.ApplicationPhysicalPath in building the path to the xml and xsd files.
However in an unit test you could call the other constructor like this:
const string mockDirectory = "TEST";
var expectedXmlPath = Path.Combine(mockDirectory, "App_Data", "MyDataRecords.xml");
string xmlPathPassed = "";
var service = new MyService(path =>
{
xmlPathPassed = path;
return XDocument.Parse("<note><to>Tove</to><from>Jani</from><heading>Reminder</heading><body>Don't forget me this weekend!</body></note>");
},
() => mockDirectory);
Assert.Equal(expectedXmlPath, xmlPathPassed);
You could also expose the XDocument on the Service, perhaps through a readonly property and check that the XDocument represents the Mocked xml.
MyService:
public class MyService : IMyService
{
private const string AppDataDirectoryName = "App_Data";
private const string SchemaFileName = "schema_0.1.xsd";
private const string XmlFileName = "MyDataRecords.xml";
private readonly Func<string, XDocument> mdocumentLoader;
private readonly Func<string> mAppDataDirectoryBuilder;
private readonly string mSchemaPath = "";
private readonly string mXmlPath = "";
private XDocument mXDocument;
public MyService() : this(XDocument.Load, () => HostingEnvironment.ApplicationPhysicalPath)
{
}
public MyService(Func<string, XDocument> documentLoader, Func<string> appDataDirectoryBuilder)
{
mdocumentLoader = documentLoader;
mAppDataDirectoryBuilder = appDataDirectoryBuilder;
try
{
var baseDirectory = mAppDataDirectoryBuilder();
mSchemaPath = Path.Combine(baseDirectory, AppDataDirectoryName, SchemaFileName);
mXmlPath = Path.Combine(baseDirectory, AppDataDirectoryName, XmlFileName);
mXDocument = mdocumentLoader(mXmlPath);
if (mXDocument == null)
{
throw new Exception("Null returned while reading xml file");
}
}
catch (Exception e)
{
//my exception management code
}
}
public List<MyRecord> GetAllRecords()
{
////fetch records from xDocument
return null;
//mXDocument.Save();
}
public void AddRecord(MyRecord record)
{
////add record
// mXDocument.Save(record);
}
}

[assembly: InternalsVisibleTo("MyService.UnitTests")]
public class MyService : IMyService
{
private readonly string mSchemaPath;
private readonly string mXmlPath;
public MyService()
: this(
Path.Combine(HostingEnvironment.ApplicationPhysicalPath, "App_Data", "MyDataRecords.xml"),
Path.Combine(HostingEnvironment.ApplicationPhysicalPath, "App_Data", "schema_0.1.xsd"))
{
}
internal MyService(string xmlPath,string schemaPath)
{
try
{
mXmlPath=xmlPath;
mSchemaPath=schemaPath;
//load xml document
mXDocument = Xdocument.Laod(mXmlPath);
if (mXDocument == null)
{
throw new Exception("Null returned while reading xml file");
}
}
catch (Exception e)
{
//my exception management code
}
}
public List<MyRecord> GetAllRecords()
{
////fetch records from xDocument
mXDocument.Save();
}
public void AddRecord(MyRecord record)
{
////add record
mXDocument.Save();
}
}

Related

Multithread Singeleton Substitution with NSubstitute

I have a public method ValidateWords inside FooService.To test the ValidateWord method, I created IAppSettingWrapper and AppSettingWrapper which returns the Instance of AppSettings.
Inside the test method, I want to substitute NotAllowedWords using NSubstitute. However, it throws an object reference exception. Is there any way for substitution? If it's not possible, how can I refactor my static instance?
public sealed class AppSettings
{
private static object _lockObject = new object();
private static volatile AppSettings? _instance;
private static DateTime _cacheTime;
private Settings[] _settings;
public AppSettings()
{
try
{
_settings = GetSettings();
}
catch { }
}
public static AppSettings Instance
{
get
{
lock (_lockObject)
{
if (_instance == null)
{
_instance = new AppSettings();
}
}
return _instance;
}
}
public List<string> NotAllowedWords
{
get
{
return new List<string>() {
"index",
"change"
};
}
}
public T GetValues<T>(string key,T defaultValue)
{
T result = defaultValue;
var settings = _settings.Where(i => i.Key == key).FirstOrDefault();
result = (T)Convert.ChangeType(settings.Value, typeof(T));
return result;
}
private Settings[]? GetSettings()
{
//gets data from web services
return base.Channel.GetSettings();
}
}
public class Settings
{
public string Key { get; set; }
public string Value { get; set; }
}
public interface IAppSettingsWrapper
{
public AppSettings Instance();
}
public class AppSettingsWrapper : IAppSettingsWrapper
{
public AppSettings Instance()
{
return AppSettings.Instance;
}
}
[TestClass]
public class FooServiceTest{
private IAppSettingsWrapper _appSettingsWrapper;
[TestInitialize]
public void TestInitialize(IAppSettingsWrapper appSettingsWrapper)
{
_appSettingsWrapper = Substitute.For<IAppSettingsWrapper>();
}
private FooService CreateFooService()
{
return new FooService(_appSettingsWrapper);
}
[TestMethod]
public void Throw_Exception_When_Given_Word_Not_Allowed() {
var service = this.CreateFooService();
_appSettingsWrapper.Instance().NotAllowedWords.Returns(new List<string> { "index" });
var word = "index";
Exception ex = Assert.ThrowsException<Exception>(() => service.ValidateWords(word));
Assert.AreEqual("this word is not allowed", ex.Message);
}
}
public class FooService
{
private IAppSettingsWrapper _appSettingsWrapper;
public FooService(IAppSettingsWrapper appSettingsWrapper)
{
_appSettingsWrapper = appSettingsWrapper;
}
public void ValidateWords(string word)
{
if (_appSettingsWrapper.Instance().NotAllowedWords.Contains(word))
{
throw new Exception("this word is not allowed");
}
}
}
The AppSettings.NotAllowedWords property is not substitutable due to it not being virtual and the class being sealed. If you add NSubstitute.Analyzers to your test project it will help you find these cases. (The How NSubstitute Works documentation outlines why this is the case.)
One option is to make AppSettings implement an IAppSettings interface and inject that into FooService (rather than the wrapper). Then you can use a substitute for tests, and AppSettings.Instance for your real code.

Proper Way to Test a file method with .net

I'm new to .net and testing. My following code looks like this:
using System.Xml.Linq;
public class AnimalXmlService
{
public Animal GetAnimalInfoFromXml(string url) {
XElement xml_doc = GetXmlInfo(url);
if (xml_doc == null)
{
return null;
} else {
XElement animal_info = xml_doc.Element("Animal");
string animal_name = GetAnimalName(animal_info);
int animal_id = GetAnimalId(animal_info);
return new Animal(animal_id, animal_name);
}
}
private XElement GetXmlInfo(string url)
{
try
{
XElement animal_xml_info = XElement.Load(url);
return animal_xml_info;
}
catch
{
return null;
}
}
private int GetAnimalName(XElement animal_info)
{
....
}
}
My question is how do I stub the GetAnimalInfoFromXml to return a file? I have the sample xml file that I will be using instead of making a request. Here's my following test. I'm also wondering if there are better ways to refactor this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NUnit.Framework;
namespace AnimalXmlService
{
[TestFixture]
public class AnimalXmlTest
{
[Test]
public void extracts_valid_name()
{
//get xml file?
animalService AnimalXmlService = new AnimalXmlService();
name = animalService.GetAnimalName(xml_file);
Assert.AreEqual(name, "bobby the tiger");
}
[Test]
public void extracts_valid_id()
{
//get xml file?
xml_file = fetch_file //is this appropriate?
animalService AnimalXmlService = new AnimalXmlService();
id = animalService.GetAnimalId(xml_file);
Assert.AreEqual(name, "2");
}
}
}
In this situations you can use test doubles.
First , you should make your codes more testable ( Breaking dependency )
public class AnimalXmlService
{
private readonly IXmlReader _xmlReader;
public AnimalXmlService(IXmlReader xmlReader)
{
this._xmlReader = xmlReader;
}
public Animal GetAnimalInfoFromXml(string url)
{
XElement xml_doc = _xmlReader.Load(url);
if (xml_doc == null)
{
return null;
}
else
{
XElement animal_info = xml_doc.Element("Animal");
string animal_name = GetAnimalName(animal_info);
int animal_id = GetAnimalId(animal_info);
return new Animal(animal_id, animal_name);
}
}
}
And then you should create a stub to replace your real dependency. ( Also you can use frameworks like NSubstitute,Mock,...)
public class XmlReaderStub : IXmlReader
{
public XElement XElement { get; set; }
public XElement Load(string url)
{
return XElement;
}
}
And finally
public class AnimalXmlTest
{
[Test]
public void extracts_valid_name()
{
var stub = new XmlReaderStub();
stub.XElement = new XElement(); // some XElement
animalService AnimalXmlService = new AnimalXmlService(stub);
name = animalService.GetAnimalName();
Assert.AreEqual(name, "bobby the tiger");
}
}
You can have another method in your class like the one below which returns an XmlDocument.
public XmlDocument GetXmlFile()
{
XmlDocument doc = new XmlDocument();
doc.LoadXml("<Animal><Name>Bobby the tiger</Name></Animal>");
return doc;
}

How to give testcase name to log4net log file for every separate test case

I tried implementing log4net for my automation framework.
I have not written the XML config file. I have used code file only for configuring it.
class log4netHelper
{
private static ILog _logger;
private static ConsoleAppender _conAppender;
private static FileAppender _fileAppender;
private static RollingFileAppender _rollingFileAppender;
private static string _layout = "%date{ABSOLUTE} [%class] [%level] [%method] - %message%newline";
public static string Layout
{
set { _layout = value; }
}
private static PatternLayout GetPatternLayout()
{
var patternLayout = new PatternLayout()
{
ConversionPattern = _layout
};
patternLayout.ActivateOptions();
return patternLayout;
}
private static ConsoleAppender GetConsoleAppender()
{
var consoleAppender = new ConsoleAppender()
{
Name = "ConsoleAppender",
Layout = GetPatternLayout(),
Threshold = Level.Error
};
consoleAppender.ActivateOptions();
return consoleAppender;
}
private static FileAppender GetFileAppender()
{
var fileAppender = new FileAppender()
{
Name = "FileAppender",
Layout = GetPatternLayout(),
Threshold = Level.All,
AppendToFile = false,
File = #"C:\FileLogger.log"
};
fileAppender.ActivateOptions();
return fileAppender;
}
private static RollingFileAppender GetRollingFileAppender()
{
var rollingFileAppender = new RollingFileAppender()
{
Name = "RollingFileAppender",
Layout = GetPatternLayout(),
Threshold = Level.All,
AppendToFile = true,
File = "RollingfileLogger.log",
MaximumFileSize = "1MB",
MaxSizeRollBackups = 15
};
rollingFileAppender.ActivateOptions();
return rollingFileAppender;
}
public static ILog GetLogger([CallerFilePath]string filename = "")
{
if (_conAppender == null)
_conAppender = GetConsoleAppender();
if (_fileAppender == null)
_fileAppender = GetFileAppender();
if (_rollingFileAppender == null)
_rollingFileAppender = GetRollingFileAppender();
BasicConfigurator.Configure(_conAppender, _fileAppender, _rollingFileAppender);
return LogManager.GetLogger(filename);
}
}
instead of the FileLogger.log file, I want the name of the test case for every test case run.
I am not able to come up with any solution yet on how to do this.
I tried changing the File variable value in GetAppender() but couldn't do.
Also tried passing the parameter filename in test case but still the file is created by the name of FileLogger.
This is just a concept how to use TestName as a log file name, but you will get an idea.
using log4net;
using log4net.Appender;
using log4net.Config;
using log4net.Core;
using log4net.Layout;
using log4net.Repository.Hierarchy;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace UnitTest
{
public static class Log4NetHelper
{
private static readonly string _layout = "%date{ABSOLUTE} [%class] [%level] [%method] - %message%newline";
private static readonly string _appenderName = "FileAppender";
private static PatternLayout GetPatternLayout()
{
PatternLayout patternLayout = new PatternLayout
{
ConversionPattern = _layout
};
patternLayout.ActivateOptions();
return patternLayout;
}
private static FileAppender GetFileAppender(string fileName)
{
var fileAppender = new FileAppender
{
Name = _appenderName,
Layout = GetPatternLayout(),
Threshold = Level.All,
AppendToFile = false,
File = $#"C:\temp\{fileName}.log"
};
fileAppender.ActivateOptions();
return fileAppender;
}
public static ILog GetLogger(string filename)
{
// Remember to clear old logger
Logger root = ((Hierarchy)LogManager.GetRepository()).Root;
root.RemoveAppender(_appenderName);
BasicConfigurator.Configure(GetFileAppender(filename));
return LogManager.GetLogger(filename);
}
}
[TestClass]
public class MyTestClass
{
public TestContext TestContext { get; set; }
private ILog log;
[TestInitialize]
public void TestInitialize()
{
log = Log4NetHelper.GetLogger($"{TestContext.FullyQualifiedTestClassName}.{TestContext.TestName}");
}
[TestMethod]
public void TestMethod1()
{
log.Info("This is my log message from TestMethod1");
Assert.IsTrue(true);
}
[TestMethod]
public void TestMethod2()
{
log.Info("This is my log message from TestMethod2");
Assert.IsTrue(true);
}
}
}
This will generate 2 files in C:\logs directory:
UnitTest.MyTestClass.TestMethod1.log
UnitTest.MyTestClass.TestMethod2.log
each with one single log message.

Moq an object in a static class

I can't get Moq to mock an object that gets created in a static method.
Here is my moq and code
code:
public interface IConfigHelper
{
string GetConfiguration(string sectionName, string elementName);
}
public class ConfigHelper : IConfigHelper
{
public ConfigHelper() { }
public virtual string GetConfiguration(string sectionName, string elementName)
{
string retValue = String.Empty;
//Does things to get configuration and return a value
return retValue;
}
}
public class myRealClass
{
public myRealClass(){}
public string myworkingMethod()
{
var retValue = String.Empty;
retValue = utilSvc.GetConfigurationValue();
return retValue;
}
}
public static class utilSvc
{
public static string GetConfigurationValue()
{
ConfigHelper configUtil = new ConfigHelper(); //NOT BEING MOCKED
return configUtil.GetConfiguration("sectionName/sectionElement", "ClinicalSystem");
}
}
the Test using Moq
[TestFixture(TestName = "Tests")]
public class Tests
{
private Mock<IConfigHelper> configHelperMOCK;
[SetUp]
public void Setup()
{
configHelperMOCK = new Mock<IConfigHelper>();
}
[Test]
public void serviceIsBPManagementForValidSource()
{
//Arrange
string sectionName = "sectionName/sectionElement";
string clinicalElementName = "ClinicalSystem";
string clinicalElementValue = "Zedmed";
configHelperMOCK.Setup(s => s.GetConfiguration(sectionName, clinicalElementName)).Returns(clinicalElementValue);
//act
// the call to myRealClass
//assert
// test assertions
}
}
The issue that I am having is with this line:
ConfigHelper configUtil = new ConfigHelper(); //NOT BEING MOCKED
I cannot get the moq to Mock the object.
I do not want the code to read the config file. I wish to moq away this instance of ConfigHelper
You can't wrap the static class/method but you can redirect it
public static class UtilSvc
{
static UtilSvc()
{
CreatorFunc = () => new ConfigHelper();
}
public static Func<IConfigHelper> CreatorFunc { get; set; }
public static string GetConfigurationValue()
{
var configUtil = CreatorFunc();
return configUtil.GetConfiguration("sectionName/sectionElement",
"ClinicalSystem");
}
}
and then in the test
//...
private Mock<IConfigHelper> configHelperMOCK;
[SetUp]
public void Setup()
{
configHelperMOCK = new Mock<IConfigHelper>();
UtilService.CreatorFunc = () => configHelperMOCK.Object;
}
//...
You cannot mock static class. I would rather propose to inject that IConfigHelper into the myRealClass. That is the usual way how to decouple dependencies and use DI.
public class myRealClass
{
private IConfigHelper _configHelper;
public myRealClass(IConfigHelper configHelper)
{
_configHelper = configHelper;
}
public string myworkingMethod()
{
var retValue = String.Empty;
retValue = _configHelper.GetConfigurationValue();
return retValue;
}
}
Avoid coupling your code to static classes, which in most cases cause you code be to difficult to maintain and test.
Follow the Explicit Dependencies Principle
Methods and classes should explicitly require (typically through
method parameters or constructor parameters) any collaborating objects
they need in order to function correctly.
Give the article a read. It is short and very informative.
If you want to keep the static class then you wrap the static class behind an abstraction.
public interface IUtilSvc {
string GetConfigurationValue();
}
public class utilSvcWrapper : IUtilSvc {
public string GetConfigurationValue() {
return utilSvc.GetConfigurationValue(); //Calling static service
}
}
Or another option is that utlSvc does not have to be static if can be injected into dependent classes
public class utilSvc : IUtilScv {
private readonly IConfigHelper configUtil;
public utilSvc(IConfigHelper configHelper) {
configUtil = configHelper;
}
public string GetConfigurationValue() {
return configUtil.GetConfiguration("sectionName/sectionElement", "ClinicalSystem");
}
}
Inject the IUtilScv into the dependent class so that it is no longer dependent on static class.
public class myRealClass {
private readonly IUtilScv utilSvc;
//Explicit dependency inject via constructor
public myRealClass(IUtilScv utilSvc) {
this.utilSvc = utilSvc;
}
public string myworkingMethod() {
var retValue = utilSvc.GetConfiguration();
return retValue;
}
}
In that case you don't even need IConfigHelper when testing as it has also been abstracted away. And you only need to mock the dependencies needed for the test.
[TestFixture(TestName = "Tests")]
public class Tests {
private Mock<IUtilScv> utilScvMOCK;
[SetUp]
public void Setup() {
utilScvMOCK = new Mock<IUtilScv>();
}
[Test]
public void serviceIsBPManagementForValidSource() {
//Arrange
var expectedClinicalElementValue = "Zedmed";
utilScvMOCK
.Setup(s => s.GetConfiguration())
.Returns(expectedClinicalElementValue)
.Verifiable();
var sut = new myRealClass(utilScvMOCK.Object);
//Act
var actualClinicalElementValue = sut.myworkingMethod();
//Assert
configHelperMOCK.Verify();
Assert.AreEqual(expectedClinicalElementValue, actualClinicalElementValue);
}
}

How to make WCF set a connection string for use with EntityFramework

Using EntityFramework, I have an auto-generated file with:
namespace Chaos.Data
{
public partial class ChaosModel : OpenAccessContext, IChaosModelUnitOfWork
{
private static string connectionStringName = #"ChaosLibraryConnection";
private static BackendConfiguration backend = GetBackendConfiguration();
private static MetadataSource metadataSource = XmlMetadataSource.FromAssemblyResource("EntitiesModel.rlinq");
public ChaosModel()
:base(connectionStringName, backend, metadataSource)
{ }
public ChaosModel(string connection)
:base(connection, backend, metadataSource)
{ }
......................
In the WCF Service, I am using:
namespace Chaos.DataService
{
[ServiceContract]
public class ChaosService
{
[OperationContract]
public IEnumerable<Encountertime> GetEncounterTimes(DateTime? encountertime)
{
if (encountertime == null) return null;
using (var context = new ChaosModel())
{
var query = from et in context.Encountertimes
where et.Tencounter.Date == ((DateTime)encountertime).Date
select et;
var result = context.CreateDetachedCopy(query.ToList());
return result;
}
}
.............................
How can I make the WCF service on startup execute a method (once) that will return a new connection string so that I can change the calls to ChaosModel() to:
using (var context = new ChaosModel(connectionString))
(I am looking for a way to add a static constructor within the WCF service--or something better?).
(The method will determine the network I am on and construct an appropriate connection string to the network server.)
Note: I can make no changes to the auto-generated Entity file.
Use static constructor.
[ServiceContract]
public class ChaosService
{
private static string connectionString;
static ChaosService(){
connectionString = your logic...
}
[OperationContract]
public IEnumerable<Encountertime> GetEncounterTimes(DateTime? encountertime)
{
using (var context = new ChaosModel(connectionString))
{
...
}
}
}
or eventually a singleton pattern:
public class ConnectionInfo
{
public string ConnectionString { get; private set; }
private ConnectionInfo()
{
var connectionstring = string.Empty;
//some logic
this.ConnectionString = connectionstring;
}
private static ConnectionInfo current;
public static ConnectionInfo Current {
get {
if (current != null)
current = new ConnectionInfo();
return current;
}
}
}
[OperationContract]
public IEnumerable<Encountertime> GetEncounterTimes(DateTime? encountertime)
{
using (var context = new ChaosModel(ConnectionInfo.Current.ConnectionString))
{
...
}
}

Categories

Resources