3

似乎测试社区的普遍共识是测试私有方法。相反,您应该通过测试调用它们的公共方法来测试私有方法。但是,我觉得有些不对劲。我们以这个方法为例:

/**
 * Returns the base name of the output generator class. If the class is named
 * Reno_OutputGenerator_HTML, this would return "HTML".
 *
 * @return string
 */
protected function getName()
{
    $class = get_class($this);
    $matches = array();

    if (preg_match('/^Reno_OutputGenerator_(.+)$', $class, $matches))
    {
        return $matches[1];
    }
    else
    {
        throw new Reno_OutputGenerator_Exception('Class name must follow the format of Reno_OutputGenerator_<name>.');
    }
}

这个特殊的功能在我班的几个地方使用。我想if在这个函数中测试语句的两个分支,这意味着对于每个公共函数,我必须测试这两种情况以及公共方法本身所做的任何其他事情。

这就是我觉得奇怪的地方。如果我正在测试是否getName()在满足某个特定条件时抛出异常,那么这意味着我必须知道私有方法的实现细节。如果我必须知道这一点,那么为什么我不应该扩展类,公开方法并以这种方式测试呢?

(顺便说一句:如果你想知道为什么存在这样一个奇怪的方法,这是用来自动找出这个类的模板文件存储在哪个目录中的)。

4

2 回答 2

2

我理解单元测试的方式,这正是我想做的那种测试。我一直将单元测试视为白盒测试;如果我的代码中有一个分支点,这意味着我需要两个单元测试来解决它。我认为我遇到的最糟糕的情况是使用 32 种排列的单一方法。

单元测试的挑战在于,如果您不通过检查代码并找出所有不同的路径来探索所有边缘案例,您最终会错过一个或多个案例,并可能在您的应用程序中引入细微的错误。

所以,不,我不认为你的提议很奇怪。该方法可以保留在内部,并且您可以添加一个额外的测试用例——您可能只需要有例外的那个,对吧?

或者,您可以将功能重构为一个单独的对象,该对象接受您的生成器对象并返回其名称(基于上述算法)。这将证明分离测试是合理的,因为您将拥有一个名称提取器对象和输出生成器实现。我仍然不确定这是否会为您节省很多,因为您仍然必须测试输出生成器以确保它们正确使用名称提取器,但它会将您的功能和测试问题分开。

于 2010-09-28T01:17:29.787 回答
0

您还可以通过从 testclass 中的类派生来测试此功能,如下所示:

namespace TheProject
{
    public class ClassUnderTest
    {
        protected string GetName()
        {
            return "The name";
        }
    }
}

namespace TestProject
{
    [TestClass]
    public class TheTest:TheProject.ClassUnderTest
    {
        [TestMethod]
        public void TestGetName()
        {
            string expected = "The name";
            string actual = GetName();
            Assert.AreEqual(expected, actual);
        }
    }
}

这样你就可以保持你的方法私有,并且你不需要将你的代码重构到另一个类。

于 2010-09-28T05:44:20.603 回答