Proper Way to Test a file method with .net - c#

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;
}

Related

How do I separate my code into their own separate classes?

How do I separate my code into their own classes and still have it function the same? This is currently what my code looks like.
using System;
using System.Collections.Generic;
using System.Xml;
using XCENT.JobServer.JobPlugIn;
using System.IO;
using HPD.API.Utility.DataAccess;
namespace DataPurge
{
public class Purge : IJob, IJobControl {
public IJobControl JobControl { get { return ( this ); } }
public int MaxInstanceCount { get { return 1; } }
public string Name { get { return "DataPurge"; } }
public Purge() { }
public void Run( string XmlFragment ) {
XmlNode xmlNode = null;
try
{
xmlNode = Common.ConstructXmlNodeFromString(XmlFragment, "Params");
var list = DataList();
foreach (var item in list)
{
var factory = new PurgerFactory(item);
IPurger purge = factory.Purger;
purge.Purge();
purge = null;
factory = null;
}
}
catch (Exception ex)
{
throw;
}
}
public interface IPurger
{
void Purge();
}
public enum PurgeType
{
File,
Database,
}
public class FilePurger : IPurger
{
private Parameters parameter;
public FilePurger(Parameters parameter)
{
this.parameter = parameter;
}
public void Purge()
{
var files = new DirectoryInfo(parameter.FilePath).GetFiles();
foreach (var file in files)
{
if (DateTime.Now - file.CreationTime > TimeSpan.FromDays(7))
{
File.Delete(file.FullName);
}
}
}
}
public class DbPurger : IPurger
{
private Parameters parameter;
public DbPurger(Parameters parameter)
{
this.parameter = parameter;
}
public void Purge()
{
var access = new SqlDataAccess();
var sqlParams = new Dictionary<string, object>();
sqlParams.Add("#OlderThanDays", parameter.OlderThanDays);
access.ExecuteNonQuery(parameter.CString, parameter.SPName, sqlParams, 30, false);
}
}
private List<Parameters> DataList()
{
var sqlParams = new SqlDataAccess();
var list = sqlParams.GetDataTableAsList<Parameters>("Data Source = MYSERVER; Initial Catalog = MYDATABASE; User ID = UID; Password = PASSWORD;", "purge.spoDataTable", null);
return list;
}
public class PurgerFactory
{
public IPurger Purger { get; set; }
public PurgerFactory(Parameters parameter)
{
PurgeType type = (PurgeType)Enum.Parse(typeof(PurgeType), parameter.PurgeType);
switch (type)
{
case PurgeType.File:
Purger = new FilePurger(parameter);
break;
case PurgeType.Database:
Purger = new DbPurger(parameter);
break;
default:
throw new NotImplementedException();
}
}
}
/// <summary>
/// Used to submit a job via the job monitor
/// </summary>
public XmlNode JobXMLNode => Common.ConstructXmlNodeFromString("" +
"<JobParams>" +
" <Param Name=\"InfrastructureAPI\" DataType=\"String\">" +
" <Description>Infrastructure API URL.</Description>" +
" </Param>" +
" <Param Name=\"EnvironmentName\" DataType=\"String\">" +
" <Description>The current environment.</Description>" +
" </Param>" +
"</JobParams>",
"JobParams");
}
}
Currently all parts of the program are stuffed into this one single class. I want to separate them out into their own separate classes to make the code much cleaner but still have it function the same. I'm still a beginner coder and don't know the first place to start. Any help would be much appreciated!
You should create a file IPurger.cs for the interface IPurger, then a file FilePurger.cs for the class FilePurger, the file DbPurger.cs for the class DbPurger and lastly PurgerFactory.cs for the class PurgerFactory.
That should clean up your code quite well.
If that enum is used from multiple places, you may want to place it in its own class too, perhaps a generic Enums.cs.

Using Moq with NUnit in C#

I am building a simple Airport program where planes can only take off / land if the weather is sunny and not stormy. This depends on the Weather class (which randomises the weather between sunny and stormy). However, for my tests, I want to mock the weather so I can test for all cases.
Here is my Weather.cs:
using System;
namespace ClassNameWeather
{
public class Weather
{
public Weather()
{
}
public string Forecast()
{
Random random = new Random();
var weather = random.Next(1, 11);
if (weather == 1 || weather == 2)
{
return "stormy";
}
else
{
return "sunny";
}
}
}
}
Here is my Airport.cs:
using System;
using System.Collections.Generic;
using ClassNamePlane;
using ClassNameWeather;
namespace ClassNameAirport
{
public class Airport
{
private string _AirportName { get; set; }
public List<Plane> planes;
private Weather _weather = new Weather();
public Airport(string _airportName, Weather weather)
{
planes = new List<Plane>();
_AirportName = _airportName;
}
public void Land(Plane plane)
{
if (_weather.Forecast() != "stormy")
{
planes.Add(plane);
Console.WriteLine($"{ plane.Name } has landed at {_AirportName}");
}
else
{
throw new Exception("It's too stormy to land");
}
}
public void TakeOff(Plane plane)
{
if (_weather.Forecast() != "stormy")
{
planes.Remove(plane);
Console.WriteLine($"{ plane.Name } has departed from {_AirportName}");
}
else
{
throw new Exception("It's too stormy to take off");
}
}
public int GetPlaneCount()
{
Console.WriteLine($"Number of planes at {_AirportName}: {planes.Count}");
return planes.Count;
}
public void GetPlaneNames()
{
planes.ForEach(plane => Console.WriteLine((plane as Plane).Name));
}
public List<Plane> GetPlaneList()
{
return planes;
}
}
}
And here is the test that I'm trying to use the mock in:
using NUnit.Framework;
using ClassNameAirport;
using ClassNamePlane;
using ClassNameWeather;
using Moq;
namespace AirportTest
{
public class AirportTest
{
Airport airport = new Airport("TestAirport", weather);
Plane plane = new Plane("TestPlane");
[Test]
public void PlaneCanLand()
{
var weather = new Mock<Weather>();
weather.Setup(x => x.Forecast()).Returns("sunny");
airport.Land(plane);
Assert.IsTrue(airport.planes.Contains(plane));
}
public void PlaneCanTakeOff()
{
airport.Land(plane);
airport.TakeOff(plane);
Assert.IsFalse(airport.planes.Contains(plane));
}
}
}
This line: Airport airport = new Airport("TestAirport", weather); is not working, saying the name weather does not exist.
Can anyone help me to make sure I am using Moq correctly? I'm new to C# and any advice is much appreciated.
Thank you!
UPDATE
I have fixed this, but now receive the following error:
System.NotSupportedException : Unsupported expression: x => x.Forecast()
Non-overridable members (here: Weather.Forecast) may not be used in setup / verification expressions.
Does anyone know how to fix this please?
You can introduce interface IWeather like
public interface IWeather
{
string Forecast();
}
Than implement it in Weather class. Pass IWeather reference to AirPort class and setup a mock for that.
var weather = new Mock<IWeather>();
weather.Setup(x => x.Forecast()).Returns("sunny");
...
var airport = new Airport("TestAirport", weather.Object)
And do not initialize it in Airport class directly private Weather _weather = new Weather(); (your constructor argument is not used), do like this
public class Airport
{
private string _AirportName { get; set; }
public List<Plane> planes;
private readonly IWeather _weather;
public Airport(string _airportName, IWeather weather)
{
planes = new List<Plane>();
_weather = weather;
}
...
}
You have not declared the variable weather. I suggest that you create an Initialize method and attribute it with TestInitialze
[TestInitialize]
public void TestInitialize()
{
var weather = new Mock<Weather>();
var airport = new Airport("TestAirport", weather)
}

Removing and Adding content with Code Fix Provider

I had that previous question which was intended to resolved the state of a local variable / parameter. It works fine, I tweak it a little bit and it looks like this now :
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using System.Collections.Immutable;
using System.Linq;
namespace RefactoringEssentials.CSharp.Diagnostics
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class LocalVariableNotUsedAnalyzer : DiagnosticAnalyzer
{
private static readonly DiagnosticDescriptor descriptor = new DiagnosticDescriptor(
CSharpDiagnosticIDs.LocalVariableNotUsedAnalyzerID,
GettextCatalog.GetString("Local variable is never used"),
GettextCatalog.GetString("Local variable is never used"),
DiagnosticAnalyzerCategories.RedundanciesInDeclarations,
DiagnosticSeverity.Warning,
isEnabledByDefault: true,
helpLinkUri: HelpLink.CreateFor(CSharpDiagnosticIDs.LocalVariableNotUsedAnalyzerID)
);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(descriptor);
public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction(
(nodeContext) =>
{
Diagnostic diagnostic;
if (TryGetDiagnostic(nodeContext, out diagnostic))
{
nodeContext.ReportDiagnostic(diagnostic);
}
},
SyntaxKind.LocalDeclarationStatement
);
}
private static bool TryGetDiagnostic(SyntaxNodeAnalysisContext nodeContext, out Diagnostic diagnostic)
{
diagnostic = default(Diagnostic);
if (nodeContext.IsFromGeneratedCode())
return false;
var localDeclarationUnused = nodeContext.Node as LocalDeclarationStatementSyntax;
var body = localDeclarationUnused?.Parent as BlockSyntax;
if (body == null)
return false;
var dataFlow = nodeContext.SemanticModel.AnalyzeDataFlow(body);
var variablesDeclared = dataFlow.VariablesDeclared;
var variablesRead = dataFlow.ReadInside.Union(dataFlow.ReadOutside);
var unused = variablesDeclared.Except(variablesRead).ToArray();
if (unused == null)
return false;
if (localDeclarationUnused.Declaration == null || !localDeclarationUnused.Declaration.Variables.Any())
return false;
var localDeclarationSymbol = nodeContext.SemanticModel.GetDeclaredSymbol(localDeclarationUnused.Declaration.Variables.FirstOrDefault());
if (unused.Any())
{
if (unused.Contains(localDeclarationSymbol))
{
diagnostic = Diagnostic.Create(descriptor, localDeclarationUnused.Declaration.GetLocation());
return true;
}
}
return false;
}
}
}
I have build a code fix provider which is working around 40% of the time, when checking the success rate of the NUnit test. Even though I know the code is OK, there seem to be some error on my machine that only arrives when the code fix is being run. I know this because I can debug the analyzer for the tests and each one are fine.
When the code fix provider is being run, I have this error that I can't shake for some reason : "System.ArgumentNullException : Value cannot be null.
Parameter name : declaration"
I have tried debugging the code fix provider, but nothing showed me where that declaration parameter could be located.
Moreover, I am used with code fix providers that need to either replace and remove nodes. But I'm not used to fix an error and add content and I'm wondering how to do such a thing.
Here's my code fix provider which does not take care of adding information at the moment :
using Microsoft.CodeAnalysis;
using System.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CodeFixes;
using System.Threading.Tasks;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace RefactoringEssentials.CSharp.Diagnostics
{
[ExportCodeFixProvider(LanguageNames.CSharp), System.Composition.Shared]
public class LocalVariableNotUsedCodeFixProvider : CodeFixProvider
{
public override ImmutableArray<string> FixableDiagnosticIds
{
get
{
return ImmutableArray.Create(CSharpDiagnosticIDs.LocalVariableNotUsedAnalyzerID);
}
}
public override FixAllProvider GetFixAllProvider()
{
return WellKnownFixAllProviders.BatchFixer;
}
public async override Task RegisterCodeFixesAsync(CodeFixContext context)
{
var document = context.Document;
var cancellationToken = context.CancellationToken;
var span = context.Span;
var diagnostics = context.Diagnostics;
var root = await document.GetSyntaxRootAsync(cancellationToken);
var diagnostic = diagnostics.First();
var node = root.FindNode(context.Span);
if (node == null)
return;
var newRoot = root.RemoveNode(node, SyntaxRemoveOptions.KeepNoTrivia);
context.RegisterCodeFix(CodeActionFactory.Create(node.Span, diagnostic.Severity, "Remove unused local variable", document.WithSyntaxRoot(newRoot)), diagnostic);
}
}
}
and here are the tests that I'm using to make sure that the fix is ok. The last two are running just fine :-)
using NUnit.Framework;
using RefactoringEssentials.CSharp.Diagnostics;
namespace RefactoringEssentials.Tests.CSharp.Diagnostics
{
[TestFixture]
public class LocalVariableNotUsedTests : CSharpDiagnosticTestBase
{
[Test]
public void TestUnusedVariable()
{
var input = #"
class TestClass {
void TestMethod ()
{
$int i$;
}
}";
var output = #"
class TestClass {
void TestMethod ()
{
}
}";
Analyze<LocalVariableNotUsedAnalyzer>(input, output);
}
[Test]
public void TestUnusedVariable2()
{
var input2 = #"
class TestClass {
void TestMethod ()
{
$int i, j$;
j = 1;
}
}";
var output2 = #"
class TestClass {
void TestMethod ()
{
int j;
j = 1;
}
}";
Analyze<LocalVariableNotUsedAnalyzer>(input2, output2);
}
[Test]
public void TestUsedVariable()
{
var input1 = #"
class TestClass {
void TestMethod ()
{
$int i = 0$;
}
}";
var input2 = #"
class TestClass {
void TestMethod ()
{
int i;
i = 0;
}
}";
Analyze<LocalVariableNotUsedAnalyzer>(input1);
Analyze<LocalVariableNotUsedAnalyzer>(input2);
}
[Test]
public void TestUnusedForeachVariable()
{
var input = #"
class TestClass {
void TestMethod ()
{
var array = new int[10];
foreach (var i in array) {
}
}
}";
Analyze<LocalVariableNotUsedAnalyzer>(input);
}
[Test]
public void TestUsedForeachVariable()
{
var input = #"
class TestClass {
void TestMethod ()
{
var array = new int[10];
int j = 0;
foreach (var i in array) {
j += i;
}
}
}";
Analyze<LocalVariableNotUsedAnalyzer>(input);
}
}
}
Is there is anything that is not clear, I will make sure to update my thread appropriately.

Selenium C# :: Which file type can be used for object repository for better performance?

I am creating an Automation Framework using Selenium C#, currently I am working on the object repository part. So I would like to know what all types of files I can use as the Object Repository.Currently I am thinking of using either XML or Excel but I am not sure which one is better performance wise, so can any of you share your views on this and also let me know if there are any other options.
I am planning to use XmlDocument for reading xml and oledb connection for reading excel.
By Object repository i think you mean different elements, their locators and some other required attributes, because As far as i know selenium do not have concept of Object Repository inherently.
If so, you need to think about who is going to maintain this Repository,
with few thousand locators, rather than performance maintainability would be a major issue.
Also, think about making it isolated by implementing an interface, so in future if you decide to change implementation because of any issue, it will be not impact your framework.
And XML, Excel, text file(with any delimiter), a Database, json file are good contenders for this.
Selenium does not work with XML pages by default, as browsers do not show XML files as XML, but show its as converted to html files.
For the task I had used following code (its based on HTMLAgilityPack):
XmlActions.cs
namespace BotAgent.Ifrit.Core.Xml
{
using HtmlAgilityPack;
public partial class XmlActions
{
private HtmlDocument _xmlDoc;
private HtmlNode _rootNode;
public XmlActions()
{
_xmlDoc = new HtmlDocument();
}
private void Update()
{
string pageSource = Brwsr.CurrPage.PageSource.Replace("\r\n", string.Empty);
_xmlDoc.LoadHtml(pageSource);
_rootNode = _xmlDoc.DocumentNode;
}
public NodeSingle Elmnt(string xpath)
{
Update();
var currNode = _rootNode.SelectSingleNode(xpath);
return new NodeSingle(currNode);
}
public NodesMultiple Elmnts(string xpath)
{
Update();
var nodesGroup = _rootNode.SelectNodes(xpath);
return new NodesMultiple(nodesGroup);
}
}
}
XmlActions.NodeSingle.cs
using System;
namespace BotAgent.Ifrit.Core.Xml
{
using HtmlAgilityPack;
partial class XmlActions
{
public class NodeSingle
{
private readonly HtmlNode _currNode;
public string Text
{
get
{
return CleanUpStringFromXml(_currNode.InnerText);
}
}
public string TagName
{
get
{
return _currNode.OriginalName;
}
}
public string XmlInner
{
get
{
return _currNode.InnerHtml;
}
}
public string XmlOuter
{
get
{
return _currNode.OuterHtml;
}
}
public NodeSingle(HtmlNode currentNode)
{
_currNode = currentNode;
}
public bool Exist()
{
if (_currNode == null)
{
return false;
}
return true;
}
public bool AttributesExist()
{
return _currNode.HasAttributes;
}
public bool AttributeExist(string attributeName)
{
if (_currNode.Attributes[attributeName] != null)
{
return true;
}
return false;
}
public string AttributeValue(string attrName)
{
return _currNode.GetAttributeValue(attrName, string.Empty);
}
public bool HaveChildren()
{
var firstChildNode = _currNode.FirstChild;
if (firstChildNode != null)
{
return true;
}
return false;
}
public NodeSingle FirstChild()
{
HtmlNode node = null;
try
{
node = _currNode.ChildNodes[1];
}
catch (Exception)
{
//// No need to throw exception, its normal if there are no child
}
return new NodeSingle(node);
}
public NodeSingle Parent()
{
return new NodeSingle(_currNode.ParentNode);
}
private string CleanUpStringFromXml(string xml)
{
HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(xml);
var root = doc.DocumentNode;
root.RemoveAllChildren();
return root.OuterHtml.Replace(" ", string.Empty);
}
}
}
}
XmlActions.NodesMultiple
namespace BotAgent.Ifrit.Core.Xml
{
using System.Collections.Generic;
using System.Linq;
using HtmlAgilityPack;
partial class XmlActions
{
public class NodesMultiple
{
private readonly HtmlNodeCollection _nodesGroup;
public int Count
{
get
{
return _nodesGroup.Count;
}
}
public NodesMultiple(HtmlNodeCollection nodesGroup)
{
this._nodesGroup = nodesGroup;
}
public NodeSingle GetElementByIndex(int index)
{
var singleNode = _nodesGroup.ElementAt(index);
return new NodeSingle(singleNode);
}
public List<NodeSingle> GetAll()
{
return _nodesGroup.Select(node => new NodeSingle(node)).ToList();
}
}
}
}
I had used my own framework code here, but this must not create problem for you to change it to clear selenium code.
After this you can create static XML var with browser instance and use like this:
bool isIdExist = Brwsr.Xml.Elem(".//div[1]").AttributeExist("id");
or
bool haveChild = Brwsr.Xml.Elem(".//div[1]").FirstChild().Exist;

Mocking xml file for unit testing with Rhinomocks

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();
}
}

Categories

Resources