我真的进入了TDD,我开始在jUnit中使用mockito来提高我测试代码的能力。我真的很喜欢模仿!
我注意到我必须改变我对编码的看法,比如尽可能地将协作者传递给方法,并尽可能限制构造函数中的工作。
以下情况需要来自SO专家的一些建议。
假设我有一个方法,那就是在某个类上调用一些静态方法。 E.G。
public void method(){
OtherClass.staticMethod();
}
这通常很糟糕,但在我的场景中需要它。为了使代码在单元测试中更易于测试,我想避免依赖于OtherClass并将其作为参数传递。
这不起作用,因为它会产生编译时错误。
public void method(Class<? extends OtherClass> util){
util.staticMethod();
}
...
method(OtherClass.class);
这可行,但我不喜欢实例化的OtherClass,如果我不需要,因为它只是一类静态实用程序,如方法:
public void method(OtherClass util){
util.staticMethod();
}
...
method(new OtherClass());
我向你提问: 如果不使用新关键字,是否有更好的更好的方法来实现这一目标?
答案 0 :(得分:1)
这可行,但我不喜欢实例化的OtherClass,如果我不需要,因为它只是一类静态实用程序,如方法:
public void method(OtherClass util){ util.staticMethod(); } ... method(new OtherClass());
实际上,这不起作用,因为它总是从OtherClass调用方法实现,而不管你传递的对象(即使你传递null
)。
我强烈建议不要仅使用反射来简化测试,因为这会绕过编译时检查(编译器不会检测到错误拼写的方法名称),并阻止使用IDE的许多功能(代码完成, javadoc悬停,重构支持,调用层次结构显示,跳转到定义,...)
常见的方法是使用多态分派。在Java中,这要求该方法不是静态的而不是私有的。因此经验法则是:如果需要嘲笑,它不应该是静态的。
如何最好地获取对象实例取决于您的具体情况;依赖注入(您的方法),资源定位器模式和单例模式各有其优缺点。
答案 1 :(得分:0)
在您的代码示例中:
public void method(){
OtherClass.staticMethod();
}
我的理解是,除了静态方法调用之外,上面的方法应该有一些逻辑,这就是你想要测试而不是静态方法。
如果是这样,你可以编写OtherClass.staticMethod
的模拟实现,它将绕过所有逻辑或返回所需的值或实现特定的逻辑。这将避免对OtherClass
的依赖,并为测试提供明确的控制。
答案 2 :(得分:0)
您可以通过更改此方法来使用您的第一种方法
public void method(Class<? extends OtherClass> clazz) throws Exception {
Method[] mArray = clazz.getMethods();
for(Method m :mArray) {
if(!m.isAccessible()) m.setAccessible(true);
if((m.getModifiers() & Modifier.STATIC) != 0) { // Here a method which is static is executed. You can change this condition, to suit your needs
m.invoke(null);
}
}
}
您可以通过调用
来调用它method(OtherClass.class);
没有传递该类的新对象
答案 3 :(得分:0)
你可以使用反射:
// exceptions management omitted
public void method(Class<? extends OtherClass> clazz, String methodName) {
// methodName could also be a constant if it won't change
clazz.getMethod(methodName).invoke(null);
}
然后,
method(OtherClass.class, "staticMethod");
答案 4 :(得分:0)
以下是我刚刚尝试的内容:
public void testMethod(Class<T> clazz) throws Exception{
Method m = clazz.getMethod("staticMethod",null);
m.invoke(null,null);
}
我假设(如您的示例中所述)静态方法不接受任何参数。
请参阅getMethod()和inovke()方法的文档。
答案 5 :(得分:0)
这里和那里的一些静态代码没有错 - 如果它不访问全局状态:
如果静态代码纯粹是程序性的
public void method(){ OtherClass.staticMethod(); }
只要将静态调用作为方法中唯一的操作
,就可以围绕method()进行模拟。否则,如果您的静态方法保护某些全局状态,那么使用Singleton + Locator会更好
public class Registry { DoSomethingInterface getOtherClass() { return OtherClass.getSingleton(); } } public void method(Registry reg){ reg.getOtherClass().doSomething(); }
然后,您可以将注册表子类化为getOtherClass()定位器提供所有类型的变体,这样您就可以在测试时将TestRegistry实例化,从而提供干净的全局状态和其他内容
如果您仍然需要其他类是静态的,因为您无法以任何方式更改它(即库类),您可以将其包装在您的界面中:
public class Registry { DoSomethingInterface getOtherClass() { return new DoSomethingInterface(){ public void doSomething() { OtherClass.staticMethod(); } }; } }
答案 6 :(得分:0)
我不确定这是否有帮助。但我不得不做类似的事情,虽然不是为了测试目的。这就是我想出来的。
创建一个类,一旦实例化只有一个方法,它调用另一个类静态方法。如果你想更多地解耦它,那么创建一个接口。类似的东西:
public interface MethodCaller {
void callMethod();
}
然后使用此实例作为方法的参数。
public void method(MethodCaller caller){
caller.callMethod();
}
然后打电话给你。
method(new MethodCaller() {
@Override
public void callMethod() {
OtherClass.staticMethod();
}
});
希望这有帮助!