如何对副作用逻辑进行单元测试
How to unit test side effecting logic
我有以下代码
public class Component extend Framework {
private Integer someInt;
private String someString;
public Integer getSomeInt() {
return someInt;
}
public String getSomeString() {
return someString;
}
public void activate() {
Integer tempInt = (Integer)getProperties("key"); // From Framework
if (tempInt == null) {
tempInt = (Integer)getRequest().getProperties("key"); // From Framework
}
if(tempInt == null)
tempInt = (Integer)getBind().getProperties("key"); // From Frameowrk
someString = makeServiceCall("http://.....?key=tempInt");
}
}
基本上框架调用activate()方法是为了访问框架的内部状态来构造Component对象。 activate() 有点像 Component 对象的 setter。
如果我要对上面的代码进行单元测试,最好的方法是什么而不需要框架 运行?
一种方法是模拟组件 class 并存根 super.getProperties... 调用,但是如果我们模拟有问题的 class,测试的意义何在开始?
我认为这可能是糟糕设计的味道。也许您应该考虑组合而不是继承?它将更易于测试并且更 objective。为什么 Component 继承自 Framework class?
public class Component {
private int someInt;
private String someString;
private Framework framework;
public Component(Framework framework) {
this.framework = framework
}
public int getSomeInt() {
return someInt;
}
public String getSomeString() {
return someString;
}
public void activate() {
int tempInt = framework.getProperties("key"); // From Framework
if (tempInt == null) {
tempInt = framework.getRequest().getProperties("key"); // From Framework
}
if(tempInt == null)
tempInt = framework.getBind().getProperties("key"); // From Frameowrk
someString = makeServiceCall("http://.....?key=tempInt");
}
}
使用 Mockito。
监视组件 class 并模拟方法 getRequest() 和 getBind()。
最后,直接从单元测试中调用 activate() 方法。
我将展示如何测试一种边缘情况
void testServiceCallWithNoKeyPropertyFound() {
Component componentUnderTest = new Component() {
Integer getProperties(String key) {
return null; // property should not be found
}
Request getRequest() {
return new Request(...); //this request should not contain a property named "key",
}
Bind getBind() {
return new Bind(...); //this bind should not contain a property named "key"
}
String makeServiceCall(String url) {
if (url.endsWith("null")) {
return success;
}
throw new AssertionError("expected url ending with null, but was " + url);
}
};
componentUnderTest.activate();
assertThat(componentUnderTest.getSomeString(), equalTo("success"));
}
使用Mockito (spys) 可以使这个例子更加简洁。但这将隐藏如何设计测试的原则。
还有一些边缘情况:
void testServiceCallWithPropertyFoundInComponent() ...
void testServiceCallWithPropertyFoundInRequest() ...
void testServiceCallWithPropertyFoundInBind() ...
我有以下代码
public class Component extend Framework {
private Integer someInt;
private String someString;
public Integer getSomeInt() {
return someInt;
}
public String getSomeString() {
return someString;
}
public void activate() {
Integer tempInt = (Integer)getProperties("key"); // From Framework
if (tempInt == null) {
tempInt = (Integer)getRequest().getProperties("key"); // From Framework
}
if(tempInt == null)
tempInt = (Integer)getBind().getProperties("key"); // From Frameowrk
someString = makeServiceCall("http://.....?key=tempInt");
}
}
基本上框架调用activate()方法是为了访问框架的内部状态来构造Component对象。 activate() 有点像 Component 对象的 setter。 如果我要对上面的代码进行单元测试,最好的方法是什么而不需要框架 运行?
一种方法是模拟组件 class 并存根 super.getProperties... 调用,但是如果我们模拟有问题的 class,测试的意义何在开始?
我认为这可能是糟糕设计的味道。也许您应该考虑组合而不是继承?它将更易于测试并且更 objective。为什么 Component 继承自 Framework class?
public class Component {
private int someInt;
private String someString;
private Framework framework;
public Component(Framework framework) {
this.framework = framework
}
public int getSomeInt() {
return someInt;
}
public String getSomeString() {
return someString;
}
public void activate() {
int tempInt = framework.getProperties("key"); // From Framework
if (tempInt == null) {
tempInt = framework.getRequest().getProperties("key"); // From Framework
}
if(tempInt == null)
tempInt = framework.getBind().getProperties("key"); // From Frameowrk
someString = makeServiceCall("http://.....?key=tempInt");
}
}
使用 Mockito。 监视组件 class 并模拟方法 getRequest() 和 getBind()。 最后,直接从单元测试中调用 activate() 方法。
我将展示如何测试一种边缘情况
void testServiceCallWithNoKeyPropertyFound() {
Component componentUnderTest = new Component() {
Integer getProperties(String key) {
return null; // property should not be found
}
Request getRequest() {
return new Request(...); //this request should not contain a property named "key",
}
Bind getBind() {
return new Bind(...); //this bind should not contain a property named "key"
}
String makeServiceCall(String url) {
if (url.endsWith("null")) {
return success;
}
throw new AssertionError("expected url ending with null, but was " + url);
}
};
componentUnderTest.activate();
assertThat(componentUnderTest.getSomeString(), equalTo("success"));
}
使用Mockito (spys) 可以使这个例子更加简洁。但这将隐藏如何设计测试的原则。
还有一些边缘情况:
void testServiceCallWithPropertyFoundInComponent() ...
void testServiceCallWithPropertyFoundInRequest() ...
void testServiceCallWithPropertyFoundInBind() ...