我是JUnit的新手,正在寻求建议。为了开始自己,我选择了一个简单的帮助对象,用于管理字符串表。这些测试的进展与我所阅读的指南中鼓励的粒度相反。
尝试在不重复测试的情况下保持粒度良好,我已经为相关方法创建了一些测试,例如AddAndSize或GetAndPut。但是,拥有在多个测试中设置测试的代码似乎很奇怪,我真的试图通过jUnit站稳脚跟并找到测试粒度的平衡。这是我的Target和TestCase -
DataTable是一个待测试的类
public class DataTable {
private ArrayList<String> columnNames = new ArrayList<String>();
private ArrayList<ArrayList<String>> theData = new ArrayList<ArrayList<String>>();
public DataTable() {
}
public int size() {
return theData.size();
}
public int cols() {
return columnNames.size();
}
public void addCol(String name) {
this.columnNames.add(name);
}
public int getCol(String name) {
return columnNames.indexOf(name);
}
public String getCol(int index) {
if (index < 0 | index >= columnNames.size()) {return "";}
return columnNames.get(index);
}
public String getValue(int row, String name) {
return getValue(row,this.getCol(name));
}
public String getValue(int row, int col) {
if (row < 0 | row >= theData.size()) {return "";}
if (col < 0 | col >= theData.get(row).size()) {return "";}
return theData.get(row).get(col);
}
public ArrayList<String> getNewRow() {
ArrayList<String> newRow = new ArrayList<String>();
this.theData.add(newRow);
return newRow;
}
}
以下是我写过的测试用例。
public class DataTableTest {
/**
* Test Constructor
*/
@Test
public void testDataTableConstruction() {
DataTable table = new DataTable();
assertNotNull(table);
}
/**
* Test GetNewRow and Size
*/
@Test
public void testGetNewRowAndSize() {
DataTable table = new DataTable();
assertEquals(0, table.size());
ArrayList<String> row = table.getNewRow();
assertNotNull(row);
assertEquals(1, table.size());
}
/**
*
*/
@Test
public void testColsAndAddCol() {
DataTable table = new DataTable();
assertEquals(0, table.cols());
table.addCol("One");
table.addCol("Two");
table.addCol("Three");
assertEquals(3, table.cols());
}
/**
*
*/
@Test
public void testGetColInt() {
DataTable table = new DataTable();
table.addCol("One");
table.addCol("Two");
table.addCol("Three");
assertEquals("One", table.getCol(0));
assertEquals("Two", table.getCol(1));
assertEquals("Three", table.getCol(2));
}
/**
*
*/
@Test
public void testGetColString() {
DataTable table = new DataTable();
table.addCol("One");
table.addCol("Two");
table.addCol("Three");
assertEquals(0, table.getCol("One"));
assertEquals(1, table.getCol("Two"));
assertEquals(2, table.getCol("Three"));
assertEquals(-1, table.getCol("Four"));
}
/**
*
*/
@Test
public void testGetValueIntString() {
DataTable table = new DataTable();
table.addCol("One");
table.addCol("Two");
table.addCol("Three");
ArrayList<String> row = table.getNewRow();
row.add("R1C1");
row.add("R1C2");
row.add("R1C3");
row = table.getNewRow();
row.add("R2C1");
row.add("R2C2");
row.add("R2C3");
assertEquals("R1C1", table.getValue(0, "One"));
assertEquals("R1C3", table.getValue(0, "Three"));
assertEquals("R2C2", table.getValue(1, "Two"));
assertEquals("", table.getValue(2, "One"));
assertEquals("", table.getValue(0, "Four"));
}
/**
*
*/
@Test
public void testGetValueIntInt() {
DataTable table = new DataTable();
table.addCol("One");
table.addCol("Two");
table.addCol("Three");
ArrayList<String> row = table.getNewRow();
row.add("R1C1");
row.add("R1C2");
row.add("R1C3");
row = table.getNewRow();
row.add("R2C1");
row.add("R2C2");
row.add("R2C3");
assertEquals("R1C1", table.getValue(0, 0));
assertEquals("R1C3", table.getValue(0, 2));
assertEquals("R2C2", table.getValue(1, 1));
assertEquals("", table.getValue(2, 0));
assertEquals("", table.getValue(0, 3));
}
}
答案 0 :(得分:0)
我建议使用the Enclosed
runner,并为要用于测试的每个初始状态设置不同的静态嵌套类:
@RunWith(Enclosed.class)
public class DataTableTest {
@RunWith(JUnit4.class)
public static class WhenTableIsEmpty {
private final DataTable table = new DataTable();
@Test
public void rowCountShouldReturnZero() {
assertEquals(0, table.rowCount());
}
@Test
public void addingRowsShouldSucceed() {
table.addRow("row1");
assertEquals(1, table.rowCount());
}
...
}
@RunWith(JUnit4.class)
public static class WhenTableHasOneRow {
private final DataTable table = new DataTable();
@Before
public void addOneRow() {
table.addRow("row1");
}
@Test
public void rowCountShouldReturnOne() {
assertEquals(1, table.rowCount());
}
...
}
}
请注意,嵌套类必须为static
(我忽略了在此答案的初始版本中添加static
关键字)
当您在IDE中运行测试时,测试用例将具有如下可读名称:
请注意,您不需要为嵌套类使用JUnit4
运行器。您还可以使用Parameterized
或Theories
。
答案 1 :(得分:0)
我认为只有少数事情值得测试:
getCol(int)
getValue(int, String)
getValue(int, int)
getNewRow()
我这样说的原因是:您依靠ArrayList
来完成大部分功能,而且您不应该测试任何专门代表已知且经过测试的类的内容。
测试时你想做的主要事情是:
让我们进行getCol(int)
的测试。为清楚起见,我会在此处重新发布代码。
public String getCol(int index) {
if (index < 0 | index >= columnNames.size()) {return "";}
return columnNames.get(index);
}
您可以测试四件事:
index < 0 && index >= columnNames.size()
index >= 0 && index >= columnNames.size()
index < 0 && index < columnNames.size()
index >= 0 && index < columnNames.size()
或者,如果您将|
更改为||
,则只需测试三件事:
index < 0
index >= columnNames.size()
index >= 0 && index < columnNames.size()
原因是|
不会短路,并且会评估该条件的双方。
设置您的州必须逐个测试。通过这种方式,您可以清楚地了解您正在测试的内容,为什么会失败,并且可以更轻松地解决问题。我不会拼出你需要的每一个测试(因为有很多),但他们读了这样的东西:
@Test
public void testGetColWithIndexLessThanZero() {}
确定以填写每个测试的状态。如果您发现自己重复了状态生成,那么只有 那么您可以在测试中创建一个帮助方法来帮助解决这个问题。
在测试抽象类时,我应该放置&#34; Stub&#34;测试或主要源文件夹中的目标?
您无法直接实例化抽象类,因此您能够测试它的唯一方法是创建一个扩展它的类。您可以直接执行此操作(扩展抽象类的实际类),也可以在测试中创建(创建扩展抽象类的匿名类)。
答案 2 :(得分:-1)
我会像任何软件一样,将公共部分复制到一个地方等等。我的建议是:
public class MyTests {
private DataTable table;
@Before
public void setup() {
table = new DataTable();
assertEquals(0, table.size());
assertEquals(0, table.cols());
table.addCol("One");
table.addCol("Two");
table.addCol("Three");
assertEquals(3, table.cols());
}
/**
* Test GetNewRow and Size
*/
@Test
public void testGetNewRowAndSize() {
ArrayList<String> row = table.getNewRow();
assertNotNull(row);
assertEquals(1, table.size());
}
@Test
public void testGetColInt() {
assertEquals("One", table.getCol(0));
assertEquals("Two", table.getCol(1));
assertEquals("Three", table.getCol(2));
}
@Test
public void testGetColString() {
assertEquals(0, table.getCol("One"));
assertEquals(1, table.getCol("Two"));
assertEquals(2, table.getCol("Three"));
assertEquals(-1, table.getCol("Four"));
}
private void addRows() {
ArrayList<String> row = table.getNewRow();
row.add("R1C1");
row.add("R1C2");
row.add("R1C3");
row = table.getNewRow();
row.add("R2C1");
row.add("R2C2");
row.add("R2C3");
}
@Test
public void testGetValueIntString() {
addRows();
assertEquals("R1C1", table.getValue(0, "One"));
assertEquals("R1C3", table.getValue(0, "Three"));
assertEquals("R2C2", table.getValue(1, "Two"));
assertEquals("", table.getValue(2, "One"));
assertEquals("", table.getValue(0, "Four"));
}
@Test
public void testGetValueIntInt() {
addRows();
assertEquals("R1C1", table.getValue(0, 0));
assertEquals("R1C3", table.getValue(0, 2));
assertEquals("R2C2", table.getValue(1, 1));
assertEquals("", table.getValue(2, 0));
assertEquals("", table.getValue(0, 3));
}
}
不确定之前的断言是否有任何用途,如果那些不持有,任何测试都会失败。无论如何,在我看到的时候,写作测试没有特别的魔力。