4

假设我们有这个超简单的类层次结构:

public class SomeMath
{
    public int Add(int x, int y)
    {
        return x + y;
    }
}

public class MoreMath : SomeMath
{
    public int Subtract(int x, int y)
    {
        return x - y;
    }
}

当我为类编写测试时,我应该为Add方法编写测试吗?MoreMath或者我应该只在测试课程时关心那个方法SomeMath?更一般地说:我应该测试一个类的所有方法,还是应该只测试“新”方法?

我可以为双方想出一些理由。例如,在测试所有方法时,您最终会多次测试同一事物,这不是很好,而且可能会变得乏味。但是,如果您不测试所有方法,则更改SomeMath可能会破坏MoreMath? 这也将是一件坏事。我想这可能也取决于情况。就像它是否扩展了我可以控制的类。但无论如何,我是一个完全测试新手,所以我很想知道有什么人比我想的更聪明:-)

4

5 回答 5

7

通常我不会测试子类中的行为,除非子类改变了父类中预期的行为。如果它使用相同的行为,则无需对其进行测试。如果您打算对父类进行重大更改,但子类仍需要旧行为,那么我将首先在子类中创建测试以定义其所需的行为,然后我将在父测试和后续测试中进行更改代码更改。这遵循 YAGNI 原则——您将不需要它——并延迟子测试的实施,直到它们真正有目的为止。

于 2009-11-23T13:00:45.040 回答
1

我只会测试AddSomeMath 类的方法。如果MoreMath只是继承它并且完全没有做任何新的事情,那么为两者编写测试将是纯粹的重复代码,仅此而已。恕我直言,对这些事情有点务实总是好的。

于 2009-11-23T13:01:06.267 回答
1

在我现在的地方,我们遇到了一个类似的问题,我们想开发接口,但要确保接口的每个实现都表现正确(例如,不同的数据层应该表现相同,而不管该层的实现如何)。我们解决它的方法(使用 NUnit)是在单元测试中拥有一个继承结构:

public interface ICalculator
{
  public int Add(int a, int b)
}

public class Calculator : ICalculator
{
  public int Add(int a, int b) { return a + b; }
}

public class TestCalculatorInterface
{
   public abstract SomeMath GetObjectToTest();

   [Test]
   public void TestAdd()
   {
       var someMath = GetObjectToTest();
       ...
   }
}    

[TestFixture]
public class TestCalculator: TestCalculatorInterface
{
   public virtual Calculator GetObjectToTest() { return new Calculator(); }
}

我们不会在基本接口测试上具有[TestFixture]属性,但在所有测试方法上都具有[Test]属性。TestCalculator类是[TestFixture]但继承了类的所有测试,从而使子类仅负责提供对象以测试该接口。

对于您的情况,我会采用类似的模式,因此测试针对所有类运行,但只编写一次。

于 2009-11-23T13:48:26.957 回答
0

首先,我认为至少有两个因素可能会影响你决定做一个或另一个:

  • 继承的目的是什么?
  • 相关测试的目的是什么?

在 TDD 场景中,我倾向于为 MoreMath 编写一个测试用例,验证它是否派生自 SomeMath,然后考虑覆盖从 SomeMath 继承的所有成员。

然而,这意味着,从设计的角度来看,MoreMath 是从 SomeMath 派生的一个重要设计方面。如果您以多态方式使用 SomeMath,肯定会出现这种情况。但是,如果您只是使用继承进行重用,则情况并非如此(但不推荐)。

在后一种情况下(继承用于重用),父类和子类之间没有概念上的联系,将来您可能会想打破继承。在这种情况下,进行验证父母是否正确的测试是一个糟糕的保障措施。

从质量保证 (QA) 的角度来看,每个班级的每个成员都应该经过严格的测试。这意味着即使测试代码相同,您也应该为每个子类重复测试代码,因为您需要验证没有以意外方式覆盖任何虚拟方法。但是,为了保持 DRY,您可以将它们编写为参数化测试,或者使用诸如Pex之类的工具。

就个人而言,我很少进入 QA 阶段。通常,在 TDD 期间创建的测试套件是一个足够的安全网……但这一切都取决于您构建的软件类型。

于 2009-11-23T13:14:07.650 回答
0

我会让我的测试类MoreMath继承自测试类SomeMath,从而继承该类的所有测试。这意味着我只需为新功能编写额外的测试,但所有子类的功能都经过全面测试。

于 2009-11-23T13:29:46.463 回答