如何正确进行单元测试

时间:2014-11-11 16:09:46

标签: c# unit-testing

我尝试使用测试驱动设计方法编写应用程序 - 我对单元测试很陌生,所以我只是想知道测试正确输入和异常的正确方法是什么是

我有这个用于加载配置文件的类:

class Config
{
    private XmlDocument configfile;

    public Config()
    {
        configfile = new XmlDocument();
    }

    public void LoadConfigFile(string filename)
    {
        if(string.IsNullOrEmpty(filename)) 
            throw new System.ArgumentException("You must specify a filename");

        try
        {
            configfile.Load(filename);
        }
        catch (Exception ex)
        {
            throw new System.IO.FileNotFoundException("File could not be loaded");
        }
    }
}

因此,可以在此处执行3项测试:

  1. 加载实际文件并确保没有错误
  2. 尝试加载无效文件(不存在的文件)
  3. 不指定文件名参数
  4. 测试这些是正确的方法,编写3种测试方法,如此吗?:

        /// <summary>
        ///A test for LoadConfigFile
        ///</summary>
        [TestMethod()]
        public void LoadConfigFileTest()
        {
            Config target = new Config(); // TODO: Initialize to an appropriate value
            string filename = "config.xml"; // TODO: Initialize to an appropriate value
            target.LoadConfigFile(filename);
            Assert.Inconclusive("A method that does not return a value cannot be verified.");
        }
    
        /// <summary>
        ///A test for LoadConfigFile
        ///</summary>
        [TestMethod()]
        [ExpectedException(typeof(System.ArgumentException))]
        public void LoadConfigFileTest1()
        {
            Config target = new Config(); // TODO: Initialize to an appropriate value
            string filename = ""; // TODO: Initialize to an appropriate value
            target.LoadConfigFile(filename);
            Assert.Inconclusive("A method that does not return a value cannot be verified.");
        }
    
        /// <summary>
        ///A test for LoadConfigFile
        ///</summary>
        [TestMethod()]
        [ExpectedException(typeof(System.IO.FileNotFoundException))]
        public void LoadConfigFileTest2()
        {
            Config target = new Config(); // TODO: Initialize to an appropriate value
            string filename = "blah.xml"; // TODO: Initialize to an appropriate value
            target.LoadConfigFile(filename);
            Assert.Inconclusive("A method that does not return a value cannot be verified.");
        }
    

    另外,如果所有这三个测试都有try {} catch(){}语句吗? 与第一次测试一样,隐含了正确性,在第二次和第三次测试中,我无论如何都要检查异常,因此异常对测试没有影响。

1 个答案:

答案 0 :(得分:4)

你走的是正确的道路,但尚未到达。

很少有情况需要调用Assert.Inconclusive并且在您的情况下没有必要:当您预期异常并抛出异常时,它将按预期工作(又名:它应该显示为绿色结果)。当您期望异常并且没有抛出异常时,它将显示为失败(又名:红色结果)。更多关于here

事实上,a method that returns void can be tested。而不是返回值,它可能会改变某些事物的状态。在您的情况下变量configFile。测试方法的方法是检索值(例如通过提供一个getter)和/或使用依赖注入,并在测试中用变量替换假/模拟/存根(选择你的行话)。

应该没有try-catch块:它只会隐藏代码可能存在的任何问题。至于原始代码:不要捕获实际异常并将其重新抛出为FileNotFoundExceptionLook at all the possible causes you are hiding

扩展评论:

  

我不希望开发人员直接使用configfile属性,所以我应该将其公开用于测试,然后将其更改回私有?

这是一个很好的关注,并且每个开发人员在进行测试时都会面对它。重要的是要认识到单位的内部运作不是你应该通常测试的东西。实现细节正是它们的实现细节。然而,有时替代品甚至更不需要,所以你必须进行比较,无论你是否想要这样做。

这可能是一个合法的用例,幸运的是有一个相当不错的解决方法!我在其中详细介绍here但我建议internal configfile访问[InternalsVisibleTo]是否使用内部构造函数,方法,属性或仅使用字段。通过应用{{1}}属性,您可以从单元测试项目中访问它,同时仍然将其隐藏在公共场所。

  

关于使用存根来测试configfile中的内容,看起来我必须将所有内容更改为依赖于接口?这不仅会增加更多不需要的复杂性吗?

定义“需要什么”。确实,通过定义接口并注入这些接口并在代码中有一个额外的抽象层,但这样做是有原因的:由于类的松散耦合性,您现在可以通过注入另一个实现来更轻松地测试它。 / p>

此过程 - 依赖注入 - 是单元测试的支柱,也将有助于您的第一次评论。