所有课程都应该可以测试吗?

时间:2014-12-08 14:09:17

标签: c# unit-testing mocking

我正在尝试为我创建的一个新项目编写单元测试,并且我遇到了一个问题,我无法弄清楚我打算编写的类是如何实际可测试的。下面我简化了我想写的课程,让你了解我想要实现的目标。

所以我有一个XML解析器,它只需从给定的URL访问XML文件,提取我需要的数据并将其作为对象返回。所以我的代码看起来像这样(验证和人口尚未完成,但你明白了):

public UserDetails ParseUserDetails(string request, string username, string password)
{
    var response = new XmlDocument();
    response.Load(string.Format(request + "?user={0}&password={1}", username, password));

    // Validation checks

    return new UserDetails { // Populate object with XML nodes };
}

目前我的班级不可测试。我无法模拟加载以抛出WebException以查看我的类如何处理错误,并且在我通过有效的URL之前,当我针对此类运行测试时,它总是会抛出异常。我也无法测试从类中返回的数据,因为我无法模拟XML文档,因为它是从另一个URL加载的。

我可以把它拆分成一个可模拟的对象,从URL中检索XML并将其命名为IXmlDocumentLoader,但后来我遇到了同样的问题,我有这样的类:

public class XmlDocumentLoader : IXmlDocumentLoader
{
    public XmlDocument LoadXmlDocument(string request, string username, string password)
    {
        var response = new XmlDocument();
        response.Load(string.Format(request + "?user={0}&password={1}", username, password));

        return response;
    }
}

这将使ParseUserDetails方法更易于测试,但现在类XmlDocumentLoader不可测试。我刚刚把问题转移到其他地方了吗?我的问题是,所有课程都必须是可测试的,还是我误解了单元测试?

3 个答案:

答案 0 :(得分:4)

这肯定是一个"意见"问题,因此,可能会被关闭。

但我会给你一个建议。

拆分一切。使用&#34的原则;一个对象应该只做一件事"。下载文件是一回事,验证它是另一回事。如果你同时选择两者,你可以测试它们。

您可以在通用文件上测试下载系统(不必是生产站点),并测试系统是否正常工作。你可以提供一个假文件"测试验证,也不必是生产文件。

这两项测试都可以让您了解代码的运行情况。

答案 1 :(得分:2)

XmlDocument.Load(string filename) documentation in MSDN因此定义filename参数:

  

filename :包含要加载的XML文档的文件的URL。 URL可以是本地文件或HTTP URL(Web地址)。

(强调我的)

因此,如果您的ParseUserDetails测试通过file://C:/path/to/my/test/file作为request参数传递,那么您的代码完全可以测试。他们可能看起来像这样:

    public void SomeRandomTest()
    {
        string testFileLocalPath = @"C:\path\to\my\test\file";
        // Code to create an XML file with expected data goes here ...

        UriBuilder ub = new UriBuilder();
        ub.Scheme = "file";
        ub.Host = "";
        ub.Path = testFileLocalPath;
        string request = ub.ToString();

        var target = new SomethingThatReadsXml();
        var details = target.ParseUserDetails(request, "dummy", "whocares");

        // Compare returned user details to expected values here ...
    }

答案 2 :(得分:1)

这个问题并不容易,我不同意这个代码应该用于工作而不需要测试的意见。我个人会做集成测试,测试你可以在构建过程中运行的实际现实情况。

为了使LOGIC可测试,我会将这个东西分开(就像你提到的那样)并让你的Parser使用Stream(或等同物)。基于Streams的IO-Code的优点是,您可以使用MemoryStreams伪造数据,因此您可以通过测试中编写的XML代码测试您的Parser。要测试从Web检索XML并将其作为Stream返回的另一件事,模拟会有点复杂,但逻辑应该更容易,您只需要测试输入和一些无效URL /凭证的集成测试/ ......实际的检索实际上是.Net实现(你不必测试)。

最后,你将达到一个你不能伪造的外部边界,但是xml解析器不应该是那个;)

在这里你可以看到一个例子: VS Magazine

相关问题