0

I have begun to dabble in unit testing, and have created a couple of tests that test one of my presenter methods. This testing requires a mock of my data access class, and one method in particular. This is the original method from my data access class:

public IEnumerable<IArea> GetAreaList()
    {
        ConnectToTFSProject();

        XmlNode areaNode = GetAreaNode();
        List<IArea> areaList = new List<IArea>();

        foreach (XmlNode node in areaNode.FirstChild.ChildNodes)
        {
            IArea area = new Area() { AreaName = node.Attributes["Name"].Value };
            areaList.Add(area);
        }

        areaList.Sort();

        return areaList;
    }

I would like to test the presenter method with different scenarios, e.g.:

  • a regular list of areas
  • an empty list of areas
  • a list of areas with duplicates
  • a list or areas containing one empty string area

My first thought was to create a separate mock data access class for each of these scenarios. I thought this to be a little cumbersome, so I adapted the method slightly to allow the reading of different xml files, containing data specific to the current test. Here is how my mock method looks:

public IEnumerable<IArea> GetAreaList(string dataSource)
    {
        List<IArea> areaList = new List<IArea>();

        XmlTextReader areaReader = new XmlTextReader(dataSource);

        while (areaReader.Read())
        {
            if (areaReader.NodeType == XmlNodeType.Text)
                areaList.Add(new Area() { AreaName = areaReader.Value });
        }

        return areaList;
    }

This mock method will then be called from the PresenterTest class as follows:

[TestMethod]
    public void PopulateAreaComboBox_WithValidAreaList()
    {
        //Act
        _presenter.PopulateAreaComboBox(mockFolderPath + "MockAreaList.xml");

        //Assert
        Assert.AreEqual(3, _view.AreaListLoaded.Count);
    }

    [TestMethod]
    public void PopulateAreaComboBox_WithEmptyAreaList()
    {
        //Act
        _presenter.PopulateAreaComboBox(mockFolderPath + "MockEmptyAreaList.xml");

        //Assert
        Assert.AreEqual(0, _view.AreaListLoaded.Count);
    }

Now, the problem I have here is that I now need to change the signature of my original method (by adding reference to the dataSource parameter):

public IEnumerable<IArea> GetAreaList(string dataSource)

Because this parameter is required only for the unit tests, the value of null is passed into this method from the real presenter class, and never used.

I know this is wrong but how should this be accomplished? Should I create a separate mock data access class that sets up each test data scenario?

amarsha4
  • 453
  • 6
  • 21
  • Yes mocking the class with the GetAreaList Method should be the way to get. But your test itself looks wrong to me or at least to complex as a unittest. You should test if GetAreaList works and maybe if your presenter can Populate the view with data but your Testcode suggest that it test both at once? – Ralf Jun 11 '13 at 10:34

1 Answers1

0

I resolved this by exposing a public string (TestDataXml) in my mock data access class. I then created a new instance of the mock data access class for each test, setting this string to the location of an individual test data xml file each time:

class MockDataRetrieval : IDataRetrieval
{
    public string TestDataXml { get; set; }

    public IEnumerable<IArea> GetAreaList()
    {
        List<IArea> areaList = new List<IArea>();

        XmlTextReader areaReader = new XmlTextReader(TestDataXml);

        while (areaReader.Read())
        {
            if (areaReader.NodeType == XmlNodeType.Text)
                areaList.Add(new Area() { AreaName = areaReader.Value });
        }

        return areaList;
    }
}

To call the mock method from the PresenterTest class:

    [TestMethod]
    public void PopulateAreaComboBox_WithValidAreaList()
    {
        //Arrange
        _data = new MockDataRetrieval() { TestDataXml = mockFolderPath + "MockAreaList.xml" };
        _view = new MockMainForm();

        _presenter = new TestCasePresenter(_view, _data);

        //Act
        _presenter.PopulateAreaComboBox();

        //Assert
        Assert.AreEqual(3, _view.AreaListLoaded.Count);
    }

    [TestMethod]
    public void PopulateAreaComboBox_WithEmptyAreaList()
    {
        //Arrange
        _data = new MockDataRetrieval() { TestDataXml = mockFolderPath + "MockEmptyAreaList.xml" };
        _view = new MockMainForm();

        _presenter = new TestCasePresenter(_view, _data);

        //Act
        _presenter.PopulateAreaComboBox();

        //Assert
        Assert.AreEqual(0, _view.AreaListLoaded.Count);
    }

Ralf: Thanks for your comment. This question relates to testing the Presenter.PopulateAreaComboBox method. The GetAreaList method in this example is from the mock data access class, and simply provides the method under test with test data.

amarsha4
  • 453
  • 6
  • 21