我是Java开发的新手,今天我第一次配对程序来创建测试用例。他们非常友好地大声说出他们想要解释为什么要做某些事情的事情(例如创建一个带有参数的构造函数而不是只有一个默认的构造函数等)。
虽然我可能会保留今天看到/听到的40%,但我想知道是否有一系列步骤/指导方针要遵循,最终结果是一个测试用例,这将是一个很好的起点。
我知道通常的反应无论哪种方式,我想并询问SO成员。
以下是我采取的一些说明的片段,用以表明我的想法,就回应而言。
你明白了。 这些只是我的笔记,但我想知道是否有人有一个已经进化的列表?
答案 0 :(得分:1)
列表中的内容非常不同。甚至对于其中一个主题,“完整”列表可能不太可能。大多数人会组成一本书,可能是倍数。所以这里是我的书籍清单(和其他文档),它们汇总了一个完整的列表。
有些似乎是关于一般良好的编码实践。例如,建议通过构造函数使用依赖注入(#1);好名字的重要性(#4)。很难列出关于这些的完整清单,但有一些重要的书籍。我推荐
Robert C. Martin的清洁代码
Andrew Hunt和David Thomas的实用程序员
Joshua Bloch的有效Java
有些是关于Mockito的限制,只需查看文档和一些博客文章即可。您可能还想查看PowerMock,它试图修复Mockito和其他模拟框架的一些(大多数?)技术限制。只要阅读他们所做的事情,就可以提高您对Mockitos限制的理解。
有些是关于设计测试,使代码可测试等等。您可以考虑以下书籍:
xUnit测试模式:Gerard Meszaros重构测试代码
测试驱动:Lasse Koskela的Java开发人员TDD和验收TDD
测试驱动开发:Kent Beck的例子
答案 1 :(得分:1)
你专注于单元测试的一个方面,即嘲弄。当你不能(或不想)测试该代码的一小部分时(例如数据库查询或日志记录实用程序),您可以进行模拟。
根据我的经验,单元测试有两种形式:集成和单元测试。
最重要的是,无论是哪种单元测试,你都必须明白:
在编写单元测试时,我将使用像Mockito这样的模拟库,但我不仅仅是将自己排除在外。有些时候使用Mockito不适合你想要做的测试(100次中有99次,它是在集成测试中。不要这样做。),但是当我只想模仿来自的行为时它很方便用于快乐路径或边缘案例测试的重豆/对象/ DAO。
我对测试的偏好是将它们分成三个不同的部分:
作为一个例子,假设我想测试这种方法的行为。
public List<String> shortenNamesFromDatabase(final int maxLength) {
List<String> names = dao.executeQuery("SELECT name from dbNames");
List<String> result = new ArrayList<String>();
for(String name : names) {
result.add(name.substring(0, maxLength);
}
return result;
}
我有一个对数据库的调用,以及一些转换逻辑。我不想在此层验证数据库信息,所以我会嘲笑它。在集成测试中,我确保调用数据库,从数据库中获取每个名称。
//happy path test!
@Test
public void shortenNamesFromDatabase_namesAreOnly3CharactersLong() {
//given
final int length = 3;
List<String> dbResult = Arrays.asList("Alpha","Beta", "Gamma", "Del", "Zeta12345");
Dao daoMock = mock(Dao.class);
when(daoMock.executeQuery("SELECT name from dbNames")).thenReturn(dbResult);
SomeClass testObj = new SomeClass();
//when
List<String> result = testObj.shortenNamesFromDatabase(length);
//then
for(String name : result) {
assertTrue("Name was too long!", length <= name.length());
}
}
现在假设我想测试一些边缘案例行为。如果我将最大长度设置为零,我会期待一大堆空字符串。不理想,但我最好确保边缘情况下的行为符合我的预期。
//edge-case-why-would-you-ever-do-this-for-real test
@Test
public void shortenNamesFromDatabase_zeroLengthStringsTransformed() {
//given
final int length = 0;
List<String> dbResult = Arrays.asList("Alpha","Beta", "Gamma", "Del", "Zeta12345");
Dao daoMock = mock(Dao.class);
when(daoMock.executeQuery("SELECT name from dbNames")).thenReturn(dbResult);
SomeClass testObj = new SomeClass();
//when
List<String> result = testObj.shortenNamesFromDatabase(length);
//then
for(String name : result) {
assertTrue("Name was WAY too long!", length <= name.length());
}
}
注意测试没有真正改变?这是好的事情。使用单元测试,您应该只是一次断言或验证一件事。对一个或两个边缘情况进行重大更改可能会产生代码异味。
编写测试时,请注意以下事项:
代码味道:如果您的代码难以进行单元测试,则应考虑重构。这将使测试工作更轻松,并且您的代码更易于维护。
< / LI>不要模仿快乐。只模拟你不需要验证的东西。我不需要验证数据库中的任何内容;不是查询的长度,不是我得到了我想要的确切名称,任何东西 - 所以我嘲笑它。我所做的需要验证的是转换发生得恰当。
遵循有关测试驱动开发,缺陷驱动测试和普通单元测试的常见做法。 Wikipedia是一个很好的起点,但有关于主题的书籍和闪存卡。