C# TDD交通信号灯的重构阶段-如何做到这一点?
因此,我对即将诞生的一个类C# TDD交通信号灯的重构阶段-如何做到这一点?,c#,java,unit-testing,tdd,C#,Java,Unit Testing,Tdd,因此,我对即将诞生的一个类板进行了以下测试: [TestMethod] public void Set_The_Origin_As_Violet_And_The_Query_Confirms_It() { Board board = new Board(10, 10); Color expected = Color.Violet; board.SetColorAt(0, 0, expected); Color actual = board.GetColorAt(
板进行了以下测试:
[TestMethod]
public void Set_The_Origin_As_Violet_And_The_Query_Confirms_It() {
Board board = new Board(10, 10);
Color expected = Color.Violet;
board.SetColorAt(0, 0, expected);
Color actual = board.GetColorAt(0, 0);
Assert.AreEqual(expected, actual);
}
我试着运行代码,但编译器表示Board
不存在。所以我创造了它
我试图再次运行代码,但没有效果,因为SetColorAt()和GetColorAt()方法都不存在。我创造了它们:
public void SetColorAt(int x, int y, Color color) {
}
public void GetColorAt(int x, int y) {
}
不过,并不是每件事都很好,因为我必须把颜色改成紫色。所以我将GetColorAt()改为
所以我第一次得到了绿灯
我希望我的最终代码出现在课程板上的形式如下:
public class Board
{
private Color[,] board;
public Board(int x, int y)
{
board = new Color[x, y];
}
public void SetColorAt(int x, int y, Color color) {
board[x, y] = color;
}
public Color GetColorAt(int x, int y) {
return board[x, y];
}
}
我的第一个问题是。。。。
怎么去那里?我能在上面所示的单元测试的“重构”阶段中考虑到,当删除重复时,我最终会得到这个代码吗?
如果答案是肯定的,我觉得我的单元测试是在测试一些过于“本地化”的代码。你看,测试只是检查一个像素和一种颜色,而代码本身要复杂和丰富得多
也许解决方案是增加更多的单元测试?你建议做什么
我的第二个问题是。。。
我知道以后我会想要一个IBoard
。我应该在上面的单元测试中表达这一点吗?我应该让他去吗
Board board = new Board(10, 10);
按原样创建IBoard
界面?如何应对
public void GetColorAt(int x, int y) {
return Color.Violet;
}
这里的return Color.Violet语句可以被视为数据重复,因此您可以重构这一部分。不过,最简单的方法是在调用SetColorAt时设置一个单色值
public class Board
{
private Color theColor;
public Board(int x, int y)
{
}
public void SetColorAt(int x, int y, Color color) {
theColor = color;
}
public Color GetColorAt(int x, int y) {
return theColor;
}
}
现在,您需要进行更多的测试,以显示您可以将单独的单元格设置为不同的颜色。您熟悉测试模式,对吗?你的测试就是这么做的
[TestMethod]
public void Set_The_Origin_As_Violet_And_The_Query_Confirms_It() {
// Arrange
Board board = new Board(10, 10);
// Act
board.SetColorAt(0, 0, expected);
// Assert
Color expected = Color.Violet;
Assert.AreEqual(expected, board.GetColorAt(0, 0));
}
我喜欢使用稍微修改过的表单,arrangeassertnotact-Assert。我们的想法是验证行为本身是导致我们测试的条件的原因,因为我们在行为之前断言我们的条件不满足。下面是它的外观:
[TestMethod]
public void Set_The_Origin_As_Violet_And_The_Query_Confirms_It() {
// Arrange
Board board = new Board(10, 10);
// Assert
Color expected = Color.Violet;
Assert.AreNotEqual(expected, board.GetColorAt(0, 0));
// Act
board.SetColorAt(0, 0, expected);
// Assert
Assert.AreEqual(expected, board.GetColorAt(0, 0));
}
这迫使您在第一次编写稍微不那么简单的实现。您仍然需要额外的测试来驱动GetColorAt()的完整实现;为此,我喜欢认为,编写完整实现的时候,要比在另一种特殊情况下(我想,对于这个应用程序,大概是N=3左右)假装的麻烦少一些。从您想要实现的内容的高级描述开始
- 有行和列的正方形板
- 每个董事会职位都应该有一个
颜色李>
- 董事会用户应该能够
设置特定板的颜色
位置(像素)李>
- 董事会用户应
能够得到一张照片的颜色
具体董事会位置李>
- 等等
接下来,使用小测试来驱动实现。有时从边界条件开始比较容易
When asked to get the color at a specific board position
- given a default board, and
- the row value is less than zero
- should throw argument exception
When asked to get the color at a specific board position
- given a default board, and
- the row value is greater than the highest board row
- should throw argument exception
“行值大于最高的线路板行”强制您以某种方式设置最高的线路板行。测试并不关心您是通过构造函数还是属性设置器来设置它
When constructed with board dimensions
- should set the highest board row
“应设置最高的线路板行”强制您以某种方式访问已设置的值。也许是一个属性获取者
When asked to get the color at a specific board position
- given a default board, and
- the column value is less than zero
- should throw argument exception
When asked to get the color at a specific board position
- given a default board, and
- the column value is greater than the highest board column
- should throw argument exception
“列值大于最高的board列”强制您为最高的列复制最高的行解决方案
When constructed with board dimensions
- should set the highest board column
等等
“应返回默认颜色”强制您在某处显示默认颜色。这不应该是只有测试才知道的神奇值。将其公开为板上的常量或只读值
When asked to get the color at a specific board position
- given a default board, and
- the row value is within the board space, and
- the column is within the board space, and
- the requested position has a known color
- should return the color of the board at the requested position
“请求的位置具有已知颜色”强制您建立设置板位置颜色的能力。您现在可以这样做,因为您在某个位置获取颜色的测试失败。所以把它放在一边,建立起二传手
When asked to SET the color at a specific board position
- given a default board, and
- the row value is less than zero
- should throw argument exception
When asked to set the color at a specific board position
- given a default board, and
- the row value is greater than the highest board row
- should throw argument exception
When asked to set the color at a specific board position
- given a default board, and
- the column value is less than zero
- should throw argument exception
When asked to set the color at a specific board position
- given a default board, and
- the column value is greater than the highest board column
- should throw argument exception
When asked to set the color at a specific board position
- given a default board, and
- the row value is within the board space, and
- the column is within the board space
- should set the color at the given position to the requested color
“应将给定位置的颜色设置为请求的颜色”使用get实现验证值设置是否正确。一旦您正确地实现了它,您的所有测试将再次变为绿色
只需继续构建附加功能,一次只构建一小部分
当您使用与实现无关的术语进行测试时,您可以将实现更改为使用IBoard或Ruby或其他任何东西,并且测试描述不必更改。您必须更改一些测试实施细节,但测试的既定目标不必更改。我认为您编写了一个设置颜色并获得颜色的电路板,这是一次冒险。是什么驱动了一块木板?什么需要一块板来存储颜色?黑板是颜色的存储库
董事会有太多的实施细节。看,颜色是另一个对象的属性。你真的关心电路板存储颜色还是存储这个具有颜色属性的域对象。如果以后您也存储了董事会职位的历史记录,该怎么办。然后你要用两块板,一块是彩色板,然后是历史板
您确实需要将存储机制从实际依赖特定类型的颜色(紫色、蓝色、绿色等)中抽象出来
从理解问题域开始的问题是,它会将您的设计归档。而且它也不会如此强大
对我来说,我会从一个问题开始:颜色是什么域对象的属性?那么我的测试就会生成这个域对象。据我所知,域对象可能存在于板中,也可能不存在于板中
希望这对您有所帮助。问题在于您从“这是正确的解决方案”开始。TDD是一种引导你做出好设计的技术,而不是预先确定的。我明白你的意思。但我想不出除了这个以外还有什么别的解决办法。您有一组(x,y)点,并且希望将它们存储在二维阵列中。这是实现t的最简单方法
When asked to get the color at a specific board position
- given a default board, and
- the row value is within the board space, and
- the column is within the board space, and
- the requested position has a known color
- should return the color of the board at the requested position
When asked to SET the color at a specific board position
- given a default board, and
- the row value is less than zero
- should throw argument exception
When asked to set the color at a specific board position
- given a default board, and
- the row value is greater than the highest board row
- should throw argument exception
When asked to set the color at a specific board position
- given a default board, and
- the column value is less than zero
- should throw argument exception
When asked to set the color at a specific board position
- given a default board, and
- the column value is greater than the highest board column
- should throw argument exception
When asked to set the color at a specific board position
- given a default board, and
- the row value is within the board space, and
- the column is within the board space
- should set the color at the given position to the requested color