单元测试UI方法

时间:2015-02-11 18:31:59

标签: unit-testing user-interface

我的问题很简单(可能在经验丰富的开发人员中很有名):

我如何对这种方法进行单元测试(我知道,这不是一种方法,因为它不在一个类中,但我们假设它是这样的?)

void drawRegularPolygon(int numberOfPoint, Point centerPoint, double radius)
{
    double angleDelta = 2 * PI / numberOfPoint;

    Point firstPoint = new Point(centerPoint.x + radius, centerPoint.y);

    for (int i = 1; i < numberOfPoint; i++) {
        double angle = angleDelta * i;
        Point secondPoint = new Point(centerPoint.x + radius * cos(angle), centerPoint.y + radius * sin(angle));

        DrawLine(firstPoint, secondPoint);

        firstPoint = secondPoint;
    }
}

我接受回答说&#34;在考虑测试之前你应该重构这个看起来像this&#34;。

编辑1: 我刚刚在我的代码中发现了一个错误,但我把它留在那里以了解单元测试应该如何捕获它。

编辑2: 我还想到了另一个解决方案

Array<Line> regularPolygonLines(int numberOfPoint, Point centerPoint, double radius)
{
    Array<Line> lines = new Array<Line>;

    double angleDelta = 2 * PI / numberOfPoint;

    Point firstPoint = new Point(centerPoint.x + radius, centerPoint.y);

    for (int i = 1; i <= numberOfPoint; i++) {
        double angle = angleDelta * i;
        Point secondPoint = new Point(centerPoint.x + radius * cos(angle), centerPoint.y + radius * sin(angle));

        lines.add(new Line(firstPoint, secondPoint));

        firstPoint = secondPoint;
    }

    return lines;
}

void drawRegularPolygon(int numberOfPoint, Point centerPoint, double radius)
{
    Array<Line> lines = regularPolygonLines(numberOfPoint, centerPoint, radius);

    for (Line line in lines) {
        DrawLine(line.firstPoint, line.secondPoint);
    }
}

在此版本中,可以测试regularPolygonLines方法,但drawRegularPolygon无法测试。

1 个答案:

答案 0 :(得分:1)

有很多方法可以看到这个,并且按照有用性的相反顺序,

您不测试用户界面

通常在开发应用程序时,重要的一点是应用程序功能,因此测试它计算正确的结果通常要好得多,而不是以绿色文本显示它。更糟糕的是,随着您的应用程序的开发,您从一个UI外观转移到另一个UI外观,然后整个测试套件突然被破坏,因为您从左下角到左下角移动了一个按钮,或者将绿色文本更改为黄色文本。我曾在组织中进行过一级调试(例如View Model in和MVVM应用程序),这样我就可以测试而不是测试如果我点击这个按钮会发生什么如果我运行此命令会发生什么

然而,鉴于正在开发一段实际绘制内容的代码,那么您可能想要测试它。

您可以使用UI测试框架

有很多测试框架(扩展名?),例如NUnitFormsWhite和最近WipFlash。这些可以以多种方式工作,提供相当于驱动程序,使您能够找到元素,与它们交互,或在较低级别,移动鼠标和直接单击元素。其中一些甚至提供屏幕比较功能,使您可以比较已呈现的内容与先前存储的良好渲染。

你嘲笑/伪造依赖关系并看看它们是否产生了你期望的结果 (这可能是您正在寻找的答案)

您也可以使用更多类似BDD的方法,并使用一组示例来验证已知示例。从最简单的情况开始,双面形状或线。我们可以计算出(在我们的头脑中),如果我们在100,100点周围绘制50个半径,那么我们应该得到一条从100,150到100,50的线,另一条从100,50到100,150(反之亦然) 。所以我们现在需要的是获得DrawLine(...)将得出的点的一些方法。

因此,您可以注入一个类来处理绘图,并使我们能够将其替换为模拟功能的其他东西,以便我们能够捕捉到它的动作。

public interface IDrawStuff
{
   void DrawLine(Point start, Point end);
}

public class RealDrawStuff : IDrawStuff
{

  public void DrawLine(Point start, Point end)
  {
    // call the frameworks draw line functionality
  }
}

现在我们可以简单地注入我们的Mock功能,这可以通过Mocking框架来完成,例如Moq,但是你可以更简单地理解这一点,让我们现在创建我们自己的。在这种情况下,我们只记得代码计算的点

public class MockDrawStuff : IDrawStuff
{
 private List<Tuple<Point,Point>> drawnPoints = new List<Tuple<Point,Point>>();
 public class DrawLine(Point start, Point end)
 {
    drawnPoints.Add(new Tuple<Point,Point>(start,end));
 }

 public void Verify(Tuple<Point,Point>[] expectedPoints)
 {
    foreach(var i=0; i<expectedPoints.Count; i++)
    {
       var expected = expectedPoints[i];
       var actual = drawnPoints[i];
       if (actual.Item1.X != expected.Item1.X
         || actual.Item1.Y != expected.Item1.Y
         || actual.Item2.X != expected.Item2.X
         || actual.Item2.Y != expected.Item2.Y)
       {
            throw new Exception("Fail: {0} != {1}",expected, actual); 
            //Probably wants more detail, but you get the idea
        }
    }
}

您的代码变为

public class MyPolygonRenderer
{
 private IDrawStuff renderer;

  public MyPolygonRender(IDrawStuff renderer)
  {
     this.renderer = renderer;
  }

  void drawRegularPolygon(int numberOfPoint, Point centerPoint, double radius)
 {
double angleDelta = 2 * PI / numberOfPoint;

Point firstPoint = new Point(centerPoint.x + radius, centerPoint.y);

for (int i = 1; i < numberOfPoint; i++) {
    double angle = angleDelta * i;
    Point secondPoint = new Point(centerPoint.x + radius * cos(angle), centerPoint.y + radius * sin(angle));

    // Code change here
    renderer.DrawLine(firstPoint, secondPoint);

    firstPoint = secondPoint;
  }
 }
}

这意味着我们现在终于可以将测试编写为

[TestFixure] //Assuming NUnit
public class MyPolygonRendererTests
{
   [Test]
   public void ShouldDrawASimpleLine()
   {
      //Given
      var mockDrawStuff = new MockDrawStuff();         
      var polygonRenderer = new MyPolygonRenderer(mockDrawStuff);

     //When
     polygonRenderer.drawRegularPolygon(2, new Point(100,100),50);

    //Then
    mockDrawStuff.Verify(new [] {
      new Tuple<POint,Point>(new Point (100,150), new Point(100,50)),
      new Tuple<POint,Point>(new Point (100,50), new Point(100,150))
     });
   }
}

然后你可以通过制定3分,4分等的例子来建立其他测试。