我有一个名为TestExecutor的Java类,负责starting
测试。开始测试涉及多个阶段:
- Update test repository
- Locate the test script
- Create result empty directory
- Execute command
- Parse output
- Update database
对于每个阶段,我在TestExecutor类中创建了私有方法,它们执行上面的每个操作,所有操作都包含在try-catch块中。我知道这不是一个好设计,因为我的课程做得太多,并且由于私有方法中隐藏了大量功能,因此单元测试也很痛苦。
我希望听到您重构此课程的建议,因为我不确定如何摆脱类似于上述结构的内容。代码示例如下:
public void start() throws TestExecuteException {
try {
updateRepository();
locateScript();
createResultDirectory();
executeCommand();
parseOutput();
updateDatabase();
catch(a,b,c) {
}
}
private updateRepository() {
// Code here
}
// And repeat for other functions
答案 0 :(得分:0)
你的班级对我来说还不错。
我知道这不是好设计,因为我的班级做得太多了
就班级负有单一责任而言,方法的数量并不重要。
检查template method design pattern。您的类正在执行类似于抽象Game
类正在执行的操作。
public abstract class Game {
abstract void initialize();
abstract void startPlay();
abstract void endPlay();
//template method
public final void play(){
//initialize the game
initialize();
//start game
startPlay();
//end game
endPlay();
}
}
并且由于大量功能而对单元测试也很痛苦 隐藏在私人方法中
答案 1 :(得分:0)
我想听听你重构这个课程的建议,因为我不知道如何摆脱类似于上述结构的东西
您绝对应该将SOLID原则作为编写干净,可测试的面向对象代码的起点。我在职业生涯的开始就被介绍过,并且遵循这些原则确实很有帮助。
那就是说,我首先将相关功能分组到不同的类中。例如,updateRepository()
和updateDatabase()
可以移动到名为DatabaseHelper
的单独类中。同样地,locateScript()
和createResultDirectory()
似乎是与磁盘相关的操作,可以移动到名为DirectoryHelper
的单独类。我相信你得到了它的要点。你刚刚取得的成就是关注的分离。
现在您已经有了单独的类,您需要将它们组合在一起并将它们投入使用。您的TestExecutor
可以继续使用您列出的methods
。唯一不同的是,这些方法现在将他们的工作委托给我们在上面创建的各个类。为此,TestExecutor
需要引用DatabaseHelper
和DirectoryHelper
类。您可以直接在TestExecutor
内实例化这些类。但这意味着TestExecutor
与实现紧密耦合。您可以执行的操作是询问TestExecutor
之外的代码,以提供要使用的DatabaseHelpe
和DirectoryHelper
。这称为依赖性反转到依赖注入。这种方法的优点是您现在可以将DatabaseHelper
和DirectoryHelper
的任何子类传递给TaskExecutor
,并且不必了解实现的详细信息。通过模拟这些依赖关系而不是传递实际实例,这有助于TaskExecutor
的单元测试。
我将留下其他SOLID
原则供您探索,实施和欣赏。
答案 2 :(得分:0)
我会这样做。首先,执行每个测试步骤应该具有的合同。
interface TestCommand{
void run();
}
现在将您的测试命令作为单独的类。尝试使这些命令类具有通用性,以便您可以重用相似类型的命令。现在,在您要运行测试的类中,配置测试步骤如下。
//in your test class do this.
List<TestStep> testCommands = new ArrayList<>();
testCommands.add(new UpdateRepoCommand());
testCommands.add(new LocateScriptCommand());
// and so on....
现在,按时间顺序执行所有步骤。
public void start(testSteps) throws TestExecuteException {
try {
for(TestCommand command : testCommands){
command.run()
}
catch(Exception e) {
//deal with e
}
}
此外,正如上述CKing所述,在这些测试步骤中遵循SOLID原则。注入依赖项并分别为它们编写单元测试。