2009-09-18 63 views
1

我是一个控件开发人员和单元测试的相对新手。几乎每天,我都会对由于UI交互而无法测试控件的态度进行抗争。我正在制作一个演示控件,以表明如果控件设计为可测试的,可以显着减少手动测试。目前我有50%的逻辑覆盖率,但是如果我能找到一种方法来测试一些更复杂的部分,我认为我可以将其提高到75%或更高。你如何测试产生复杂对象图的方法?

例如,我有一个具有描述控件状态的属性的类以及一个生成由多个段组成的WPF对象的方法。实施看起来是这样的:

internal PathGeometry CreateOuterGeometry() 
{ 
    double arcRadius = OuterCoordinates.Radius; 
    double sweepAngle = OuterCoordinates.SweepAngle; 
    ArcSegment outerArc = new ArcSegment(...); 

    LineSegment arcEndToCenter = new LineSegment(...); 

    PathFigure fig = new PathFigure(); 
    // configure figure and add segments... 

    PathGeometry outerGeometry = new PathGeometry(); 
    outerGeometry.Figures.Add(fig); 
    return outerGeometry; 
} 

我有一些其他的方法,像这样的占未覆盖的代码几百块,一个额外的25%的覆盖率。我原本打算测试这些方法,但拒绝了这个概念。我仍然是一个单元测试的新手,我能想到的唯一的方法来测试代码将是几种方法是这样的:

void CreateOuterGeometry_AngleIsSmall_ArcSegmentIsCorrect() 
{ 
    ClassUnderTest classUnderTest = new ClassUnderTest(); 
    // configure the class under test... 
    ArcSegment expectedArc = // generate expected Arc... 

    PathGeometry geometry = classUnderTest.CreateOuterGeometry() 
    ArcSegment arc = geometry.Figures.Segments[0]; 

    Assert.AreEqual(expectedArc, arc) 
} 

测试本身看起来不错;我会为每个预期的分段写一个。但我有一些问题:

  • 我需要测试来验证“是否第一段ArcSegment?理论上测试测试这个,但不应该每个测试只测试一件事情?这听起来像两件事。
  • 该控件至少有六个计算案例和四个边缘案例;这意味着对于每种方法我至少需要十次测试。
  • 在开发过程中,我改变了多次生成各种几何图形的方式。这会导致我不得不重写所有的测试。

第一个问题让我停顿了一下,因为它好像可能会夸大测试的次数。我想我可能不得不测试像“有x个分段吗?”和“段n是正确的类型?”,但现在我已经想得更多了,我发现方法中没有分支逻辑,所以我只需要做一次这些测试。第二个问题让我更加确信测试会有很多努力。这似乎是不可避免的。第三个问题复合了前两个问题。每次我改变计算几何图形的方式时,我都必须编辑大约40次测试,以使它们尊重新的逻辑。这也包括添加或删除测试,如果段添加或删除。

由于这三个问题,我选择编写一个应用程序和手动测试计划,将控件置于所有有趣的状态,并要求用户验证它看起来是一种特定的方式。这是错的吗?我是否高估了编写单元测试的努力?有没有其他方法来测试这可能更容易? (我目前正在学习模拟和存根;好像需要对设计进行一些重构,并最终付出大致的努力)。

+0

究竟是什么问题?这看起来更像是对单元测试的个人挫折的冗长讨论。 – 2009-09-18 15:09:15

+0

问题是带有问号的部分:“?是这个错误我是高估参与编写单元测试的工作是否有测试此的另一种方式,可能是更容易?” – OwenP 2009-09-18 15:11:00

回答

2

使用依赖注入和模拟。

为ArcSegmentFactory,LineSegmentFactory等创建接口,并将模拟工厂传递给您的类。这样,你将隔离特定于该对象的逻辑(这应该使测试更容易),并且不会取决于其他对象的逻辑。

关于测试的内容:你应该测试什么是重要的。你可能有一个你想完成任务的时间表,你可能无法测试每一件事情。 确定需要测试的东西的优先级,并按优先级顺序测试(考虑测试需要多少时间)。此外,当你已经做了一些测试,它变得更容易为其他的东西新的考验,我实在不明白的问题创造了同一个类中的多个测试...

关于修改,这就是测试的目的:允许你改变,并且不会真的担心你的改变会给世界带来混乱。

-1

教科书的方法来做到这将是移动所有的业务逻辑,其通过在GUI中的1线的方法称为库或控制器。这样你可以单元测试控制器或库而不用处理GUI。

+0

这就是我已经在做的事情。这个问题是关于测试提取逻辑的一个特定部分。 – OwenP 2009-09-18 15:42:57

+0

我看到,这方面的问题很不明确。 至于如何测试复杂的东西。随机生成是一种方法。另一种方法是研究这个问题,并用特定的边缘案例编写好的测试用例。测试很难,这就是为什么业界有庞大的质量保证团队。 – tster 2009-09-18 15:48:06

0

您可能会尝试编写一个控件生成工具来生成随机控制图并对其进行测试。这可能会产生一些你可能没有想到的数据点。

0

在我们的项目中,我们使用JUnit来执行不严格地说是单元测试的测试。例如,我们发现,挂钩一个空白数据库并将Hibernate生成的自动模式(一种对象关系映射工具)与我们的测试数据库的实际模式进行比较是有帮助的;这有助于我们用错误的数据库映射捕捉很多问题。但总的来说......你只应该在一个给定的测试方法上测试一种方法。这并不意味着你不能对它进行多重断言来检查对象的各种属性。

0

我的方法是将图转换为一个字符串(每行一个段)并将此字符串与预期结果进行比较。

如果你改变你的代码的东西,测试将开始失败,但所有你需要做的是检查故障是在正确的地方。您的IDE应为此提供并排差异。

当您确信新输出正确时,只需将其复制到旧的预期结果上即可。这将确保不会忽视错误(至少不会被忽略),测试仍然很简单,而且很快就会修复。

接下来,如果你有共同的路径部分,那么你可以把它们放到单独的字符串,并建立从这些部件测试的预期结果。这可以让你避免重复自己(如果公共部分发生变化,你只需要为所有测试更新一个地方)。

0

如果我正确理解你的例子,你试图找到一种方法来测试一大堆绘制操作是否产生给定的结果。您可以生成一组预期图像(已验证的“良好”图像的快照),并创建单元测试,这些单元测试使用绘制操作创建相同的一组图像,并将结果与图像比较。这将允许您自动执行图形操作的测试,这正是我理解您的问题所在。

+0

这几乎是我所说的一些事情。它具有分辨率问题,偶尔会有小的细节逃脱图像分析。我们仍然会进行手动验证,但是我认为测试我将正确的数字传递给绘制事物的代码会有很大的帮助。如果那个部分搞砸了,那是不可控的。 – OwenP 2009-09-18 15:46:10