idea提取代码为方法
这篇文章是“从旧代码到可测试代码”系列的一部分。 在本系列中,我们将讨论在为遗留代码编写测试之前进行重构的步骤,以及它们如何使我们的生活更轻松。
与重命名一样,提取方法有助于我们更好地理解代码。 如果您发现该方法的命名很容易,那就很有意义。 否则,您只需封装执行很多事情的代码。 有时它可能是有用的,尽管不能提取出有意义的小方法。
提取方法还会引入接缝。 现在可以模拟此方法,并且现在可以在测试代码时对其进行影响。 不使用电动工具时的窍门之一是将静态方法与实例方法包装在一起。
在我们的Person类中,我们具有GetZipCode方法:
public class Person {
String street;
public String getZipCode() {
Directory directory = Directory.getInstance();
return directory.getZipCodeFromStreet(street);
}
}
Directory.getInstance()方法是静态的。 如果我们将其提取到getDirectory方法(在Person类中)并使该方法可访问,则现在可以对其进行模拟。
public class Person {
String street;
public String getZipCode() {
Directory directory = getDirectory();
return directory.getZipCodeFromStreet(street);
}
protected Directory getDirectory() {
return Directory.getInstance();
}
}
尽管现在使用Mockito模拟getDirectory方法非常容易,但是如果我们使用PowerMockito则模拟Directory.getInstance也很容易。 是否有其他理由引入新方法?
如果仅出于测试目的,则无需进行提取。 有时,用电动工具嘲弄事物并不容易。 静态构造函数中出现的问题可能需要在测试侧进行更多处理。 使用单独的方法包装可能会更容易。
有时,无论使用哪种模拟工具,提取都可以帮助我们。 我们甚至可以在编写方法之前使用方法提取来简化测试。 模拟一个方法(而不是3个调用)更加简单安全。
如果我们的getZipCode方法看起来像这样:
public String getZipCode() {
Address address = new Address();
address.setStreet(street);
address.setCountry(country);
address.setState(state);
address.setCity(city);
Directory directory = Directory.getInstance(address);
return directory.GetZipCode();
}
即使使用了电动工具,伪造Address实例并设置其他行为设置(仅用于检索目录)也需要大量工作,这意味着需要花很长的时间进行较长的测试。 如果我们提取getDirectoryFromAddress方法:
public String getZipCode() {
Directory directory = getDirectoryFromAddress();
return directory.GetZipCode();
}
我们获得了更具可读性的代码,并且只需要模拟一行。
虽然提取有好处,但行李也要有接缝的方法。 如果该方法是私有的,并且我们使用强大的工具对其进行了模拟,则测试和代码之间的耦合会增加。 如果我们将其公开,则可以有人叫它。 如果受保护,则派生类可以调用它。 可测试性的改变是设计的改变,无论是好是坏。
idea提取代码为方法