Unit testing 关于测试驱动开发的庸俗问题
我一直对测试驱动的开发感兴趣,但当我在实际项目中尝试它时,我永远无法坚持到底。我有几个哲学问题在我尝试时不断出现:Unit testing 关于测试驱动开发的庸俗问题,unit-testing,testing,tdd,Unit Testing,Testing,Tdd,我一直对测试驱动的开发感兴趣,但当我在实际项目中尝试它时,我永远无法坚持到底。我有几个哲学问题在我尝试时不断出现: 你如何处理大的变化?当涉及到测试单个功能(一些参数、结果值、很少的副作用)时,TDD是一个不需要动脑筋的工具。但是,当您需要彻底检修一些大型的东西时,比如从SAX解析库切换到DOM解析库,又该怎么办呢?当代码处于中间状态时,如何保持测试代码重构周期?一旦您开始进行更改,您将得到一堆失败的测试,直到您完全完成大修(除非您在完成转换之前维护某种同时使用DOM和SAX的混合类,但这非常奇
select*
。后来当我回首往事时,我希望我永远不要这样做,但那是很久以前的事了,我希望我使用了一个合适的ORM
对于GUI,可以对GUI交互进行单元测试。我这样做的方式是使用来分离模型、视图和演示者。实际上,对于这种类型的应用程序,我只在Presenter和模型上进行测试,其中我使用Typemock(或)来隔离不同的层,以便一次只能集中在一个层上。我不测试视图,但我经常测试Presenter(大多数交互和bug都发生在这里) 在处理大的变化方面。。。TDD的目的是测试代码的行为以及它如何与所依赖的服务交互。如果您希望使用TDD,并且您正在从DOM解析器迁移到SAX解析器,并且您正在自己编写SAX解析器,那么您将编写测试,根据已知输入(即XML文档)验证SAX解析器的行为。SAX解析器可能依赖于辅助对象的集合,这些对象实际上可以在最初模拟出来,以测试SAX解析器的行为。当您准备好为helper对象编写实现代码时,就可以基于已知输入围绕其预期行为编写测试。在SAX解析器的示例中,您将编写单独的类来实现此行为,以便不干扰依赖于DOM解析器的现有代码。实际上,您可以创建一个IXMLParser接口,由DOM解析器和SAX解析器实现,以便您可以随意切换它们 就使用Mock或stub而言,使用Mock或stub的原因是您对测试Mock或stub的内部工作不感兴趣,但您对测试依赖于Mock或stub的内部工作感兴趣,而这正是您从单元角度真正测试的。如果您对编写集成测试感兴趣,那么您应该编写集成测试,而不是单元测试。我发现以TDD的方式编写代码对于帮助我定义代码的结构和组织非常有用,因为我要提供的行为是围绕代码的结构和组织的
我不熟悉任何现成的案例研究,但我确信它们确实存在 至于数据库角度,正如Ngu Soon Hui提到的,您应该(IMHO)使用类似的东西,它将在已知配置中设置数据库(以便您可以测试预期的结果),但实际应用程序将使用真实的数据库 对于较大的更改,我建议创建一个分支,并允许测试失败。这将为您提供一个需要更改的区域的待办事项列表,并且可能是
// Production code in class UserFormController:
void changeUserNameButtonClicked() {
String newName = nameTextBox.getText();
if (StringUtils.isEmpty(newName)) {
errorBox.showError("User name may not be empty !");
} else {
User user = engine.getCurrentUser();
user.name = newName;
engine.saveUser(user);
}
}
// Test code in UserFormControllerTest:
void testValidUserNameChange() {
nameTextBox = createMock(TextBox.class);
expect(nameTextBox.getText()).andReturn("fred");
engine = createMock(Engine.class);
User user = createMock(user);
user.setName("fred");
expectLastCall();
expect(engine.getCurrentUser()).andReturn(user);
engine.saveUser(user);
expectLastCall();
replay(user, engine, nameTextBox);
UserFormController controller = new UserFormController();
controller.setNameTextBox(nameTextBox);
controller.setEngine(engine);
controller.changeUserNameButtonClicked();
verify(user, engine, nameTextBox);
}
void testEmptyUserNameChange() {
nameTextBox = createMock(TextBox.class);
errorBox = createMock(ErrorBox.class);
expect(nameTextBox.getText()).andReturn("");
errorBox.showError("User name may not be empty !");
expectLastCall();
replay(nameTextBox, errorBox);
UserFormController controller = new UserFormController();
controller.setNameTextBox(nameTextBox);
controller.setErrorBox(errorBox);
controller.changeUserNameButtonClicked();
verify(nameTextBox, errorBox);
}