سؤال

I need to unit testing this GetData method.

    public MessageResponse GetData(XmlElement requestElement)
    {   
        MessageResponse MsgResponse = new MessageResponse();


        if (requestElement.Attributes["employeeNo"] == null){
            MsgResponse.Messages = new List<string>();
            MsgResponse.Messages.Add("Attribute employeeNo is missing");
            MsgResponse.Error = true;
            return MsgResponse;
        }
        if (requestElement.Attributes["xmlEmployeeName"] == null){
            MsgResponse.Messages.Add("Attribute xmlEmployeeName is missing");
            MsgResponse.Error = true;
            return MsgResponse;
        }
        return MsgResponse;
    }

this method needs a XmlElement parameter. how do I mock it? in my code, I first created a xmlDocument, then load the xml file.

            XmlDocument doc = new XmlDocument();
            doc.Load(xmlFilePath);
            requestElement = doc.DocumentElement;

for me to test it, first i need to create a xml file without employeeNo, the create antoher one without name, maybe alot more for other scenarios. it just seems like alot work. is there a better way to test it?

should I use moq or other testing framework to simplify the testing?

هل كانت مفيدة؟

المحلول

You can just create the element you want to test with, w/o reading a file at all:

var doc = new XmlDocument();
doc.LoadXml("<MyTestElement/>");
var myTestElement = doc.DocumentElement;
myTestElement.Attributes["employeeNo"] = "fakeId";

var response = myTestResponder.GetData(myTestElement);

//assert whatever you need to

NOTE: every time you find out that the test is too hard to write, usually this means that your class/method does too much.

I would assume, that your method verifies the input, than does something with the data provided. I would suggest that you abstract the data reading part (using some xml deserializer) to populate the data model you need for your application.

Then run validation on the result of the deserialized data. Something like:

public MessageResponse GetData(XmlElement requestElement)
{
   var data = _xmlDeserializer.Deserialize(requestElement);
   var validationResult = _validator.Validate(data);
    if (validationResult.Errors.Count > 0)
    {
         //populate errors
        return result;
    }

    _dataProcessor.DoSomethingWithData(data);
}

Take a look at FluentValidation for a nice validation library.

If you go the above route, then your tests will be much simpler.

نصائح أخرى

[TestMethod]
public void GetData_Returns_Correct_Message_When_EmployeeNo_Is_Null()
{
    var inputWithoutEmployeeNo = GetElement(@"<input></input>");

    var actual = GetData(inputWithoutEmployeeNo);

    Assert.IsTrue(actual.Error, "Error should be true when employee no. is missing");
    Assert.IsNotNull(actual.Messages);
    Assert.AreEqual(1, actual.Messages.Count);
    Assert.AreEqual("Attribute employeeNo is missing", actual.Messages[0]);
}

private XmlElement GetElement(string xml)
{
    var doc = new XmlDocument();
    doc.LoadXml(xml);
    return doc.DocumentElement;
}

While working on the unit test, I found out that the code throws a NullReferenceException. The following unit test demonstrates the issue:

[TestMethod]
[ExpectedException(typeof(NullReferenceException))]
public void GetData_Throws_NullReferenceException_When_EmployeeNo_Is_Not_Null_And_XmlEmployeeName_Is_Null()
{
    var inputWithoutEmployeeNo = GetElement(@"<input employeeNo='123'></input>");

    GetData(inputWithoutEmployeeNo);
}

Using Moq

using System;
using System.Xml;
using Moq;
using NUnit.Framework;

namespace MockXmlTest
{
    [TestFixture]
    public class MyServiceTests
    {
        private MockSetup _mockSetup;
        [SetUp]
        public void Init()
        {
            _mockSetup = MockSetup.HappySetup();
        }
        [Test]
        public void MyService_Should_Return_Guid()
        {
            //Arrange
            var myService = _mockSetup.MyService.Object;
            var id = 42;
            var expected = Guid.Empty.ToString();

            //Act
            var actual = myService.GetXml(id);

            //Assert
            Assert.AreEqual(expected, actual.FirstChild.InnerText);
        }
    }

    public class MyService : IMyService
    {
        public XmlDocument GetXml(int id)
        {
            var doc = new XmlDocument();
            //Do real stuff
            return doc;
        }
    }

    public interface IMyService
    {
        XmlDocument GetXml(int id);
    }

    public class MockSetup
    {
        public Mock<IMyService> MyService { get; set; }

        public MockSetup()
        {
            MyService = new Mock<IMyService>();
        }
        public static MockSetup HappySetup()
        {
            var mockSetup = new MockSetup();

            var mockDoc = CreateMockDoc();

            //Matches any id of an integer, returns a XmlDocument mock
            mockSetup.MyService.Setup(m => m.GetXml(It.IsAny<int>())).Returns(mockDoc);
            return mockSetup;
        }

        private static XmlDocument CreateMockDoc()
        {
            //<Main><MyGuid>00000000-0000-0000-0000-000000000000</MyGuid></Main>
            XmlDocument mockDoc = new XmlDocument();
            XmlElement el = (XmlElement)mockDoc.AppendChild(mockDoc.CreateElement("Main"));

            el.AppendChild(mockDoc.CreateElement("MyGuid")).InnerText = It.IsAny<Guid>().ToString();
            return mockDoc;
        }
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top