Java 测试驱动开发。在创建方法之前,如何为此转换编写单元测试?
我编写了以两种格式表示电路板的迷你检查程序:Java 测试驱动开发。在创建方法之前,如何为此转换编写单元测试?,java,tdd,Java,Tdd,我编写了以两种格式表示电路板的迷你检查程序:long positionID和byte[]]board。前者存储成本较低,后者更易于表示/操作。转换本身很简单(请参见下面的代码) TDD声明“编写一个失败的测试,然后编写生产代码”。如何通过表示转换实现这一点?单元测试类 assertEquals(0L,toIndex(新字节[6][6]))没有提供太多的覆盖范围。Long myPosID=42L的测试;assertEquals(myPosID,toIndex(toBoard(myPosID))不会
long positionID
和byte[]]board
。前者存储成本较低,后者更易于表示/操作。转换本身很简单(请参见下面的代码)
TDD声明“编写一个失败的测试,然后编写生产代码”。如何通过表示转换实现这一点?单元测试类assertEquals(0L,toIndex(新字节[6][6]))
没有提供太多的覆盖范围。Long myPosID=42L的测试;assertEquals(myPosID,toIndex(toBoard(myPosID))
不会增加太多的值。测试整个范围将花费永远的时间。为几个随机的myPosID
值运行单元测试(蒙特卡罗模拟)似乎更好,但即使通过测试也没有多大意义
在TDD中应该如何进行
/*
This class manipulates checkers board representation. Position is stored as long and represented as byte[height][width] board.
For board representation white = 0, black = 1, empty = 2.
Long positionID to byte[][] board:
get ternary numeral system representation of positionID, place positional values to corresponding squares.
For conversion from byte[][] board to long positionID:
long positionID = 0; for each (byte playableSquare : board){playable square positionID = positionID*3. positionID+= playableSquare}
*/
public final int boardHeight = 6;
public final int boardWidth = 6;
public long toIndex(byte[][] board) {
byte coords[] = new byte[boardHeight * boardWidth / 2];
int totalSquares = boardHeight * boardWidth / 2;
byte k = 0;
for (int i = 0; i < boardHeight; i++) {
for (int j = 0; j < boardWidth / 2; j++) {
byte makeItCheckers = (byte) ((i + 1) % 2);
coords[k] = board[i][j * 2 + makeItCheckers];
k++;
}
}
long positionID = 0;
for (int i = totalSquares - 1; i >= 0; i--) {
positionID = positionID * 3 + coords[i];
}
return positionID;
}
public byte[][] toBoard(long positionID) {
int totalSquares = boardHeight * boardWidth / 2;
int[] coords = new int[totalSquares];
for (int i = 0; i < totalSquares; i++) {
coords[i] = (int) (positionID % 3L);
positionID = positionID / 3L;
}
byte[][] board = new byte[boardHeight][boardWidth];
Arrays.fill(board, 2);
byte k = 0;
for (int i = 0; i < boardHeight; i++) {
for (int j = 0; j < boardWidth / 2; j++) {
byte makeItCheckers = (byte) ((i + 1) % 2);
board[i][j * 2 + makeItCheckers] = (byte) coords[k];
k++;
}
}
return board;
}
/*
此类处理跳棋板表示。位置存储为长,并表示为字节[高度][宽度]板。
对于电路板表示,白色=0,黑色=1,空=2。
字节[]的长位置ID板:
获取positionID的三元数字系统表示形式,将位置值放置到相应的方框中。
要将字节[]板转换为长位置ID:
long positionID=0;对于每个(字节playableSquare:board){playableSquare positionID=positionID*3.positionID+=playableSquare}
*/
公共最终内板高度=6;
公共最终int boardWidth=6;
公共长toIndex(字节[][]板){
字节坐标[]=新字节[boardHeight*boardWidth/2];
int totalSquares=板高*板宽/2;
字节k=0;
对于(int i=0;i=0;i--){
位置ID=位置ID*3+坐标[i];
}
返回位置ID;
}
公用字节[][]toBoard(长位置ID){
int totalSquares=板高*板宽/2;
int[]坐标=新的int[totalSquares];
对于(int i=0;i
TDD在编写实现之前先编写测试。你似乎做了相反的事。
要为转换处理编写TDD和更一般的单元测试,您必须考虑验收测试。
您必须确定转换处理的可能方案。
您作为输入的内容和您作为输出的预期内容。
测试整个范围将花费永远的时间 事实上,如果您有数百个甚至数千个场景,您不应该测试所有场景,因为这些场景将很长时间无法实现,而且单元测试可能会很长时间无法执行
这与单元测试原则相反。
单元测试必须快速执行,因为它们经常执行。
对几个随机myPosID值进行单元测试(蒙特卡罗) 模拟)似乎更好,但即使通过测试也不意味着 很多 使用随机值进行测试正如您所建议的那样不应使用随机序列 每次执行测试时产生的数据都不同,因为这些数据可能不可复制。
这也与单元测试原则相反。
单元测试必须在任何环境和任何时间产生相同的结果。
否则表示测试不可靠。
因此,以TDD的方式创建单元测试的想法是根据要处理的案例类型编写尽可能多的单元测试。
例如:有3种表示单元的方式: 白色=0,黑色=1,空=2 这可能是为从
Long
转换为byte[][]
和反向转换创建3个验收测试。1) 当我有一个
Long
值,只有空单元格时,我正在等待字节数组表示为
2) 当我有一个Long
值,剩下的是一个白单元格和空单元格时,我正在等待一个字节数组表示为
3) 当我有一个Long
值、一个黑色单元格和剩余的空值时,我正在等待一个字节数组表示为
然后你可以走得更远。为什么不创建一个混合黑白单元格的验收测试,以检查混合它们不会产生副作用。
4) 当我有一个
Long
值、3个白色单元格、4个黑色单元格和剩余的空单元格时,我正在等待字节数组表示为。。。
最后,关于您是否应该测试所有案例的问题,我认为您应该集中精力于上面所示的“大案例”。
应该没问题。
在竞赛编程中也存在类似的问题:当您提交代码时,系统无法验证代码的100%正确性,因为没有通过所有可能的输入。相反,系统运行许多测试,这些测试分为三类:
- 角落案例:例如,空输入
- 一些一般情况
- 测试性能的超大案例