它是几个月,因为我用java遗留代码的工作,这是一些我处理的事情:Seam和Mock有什么区别?
- 0%的测试覆盖率。
- 巨大的功能,我甚至看到一些超过300行的代码。
- 很多私人方法和场合静态方法。
- 高度紧密耦合的代码。
刚开始时我很困惑,我发现很难在传统中使用TDD。做了几个星期的katas并练习我的单元测试和嘲讽技能后,我的恐惧减少了,我感到更自信一些。最近我发现了一本名为working effectivelly with legacy的书,我没有读它,我只是看了目录,然后发现了一些对我而言是新的东西,The Seams。显然这在遗产工作中非常重要。
我认为这个Seams可以帮助我打破依赖关系,使我的代码可测试,因此我可以增加代码覆盖率并使我的单元测试更加精确。
但我有很多疑惑:
- 有人可以解释我的接缝和模拟之间的区别?
- 做测试之前,Do Seams打破了TDD规则中关于未触及生产代码的规定吗?
- 你能告诉我一些简单的例子来比较一下Seam和Mock吗?
下面我想粘贴一个我今天做过的例子,我试图打破依赖关系,使代码可测试并最终增加测试覆盖率。如果您看到一些错误,您可以评论一下,我将不胜感激?
这是遗留代码怎么看起来像开头:
public class ABitOfLegacy
{
private String sampleTitle;
String output;
public void doSomeProcessing(HttpServletRequest request) {
String [] values = request.getParameterValues(sampleTitle);
if (values != null && values.length > 0)
{
output = sampleTitle + new Date().toString() + values[0];
}
}
}
如果我只需要添加一个单元测试,调用该方法,并声称可变输出,具备呼叫后,在一定的值,然后我会犯一个错误,因为我不是单元测试,我会进行集成测试。所以我需要做的是摆脱我在参数中的依赖。要做到这一点,我有一个接口,可以取代参数:
public class ABitOfLegacy
{
private String sampleTitle;
String output;
public void doSomeProcessing(ParameterSource request) {
String [] values = request.getParameters(sampleTitle);
if (values != null && values.length > 0)
{
output = sampleTitle + new Date().toString() + values[0];
}
}
}
这是界面看起来的样子:
public interface ParameterSource {
String[] getParameters(String name);
}
接下来我要做的事情,就是创建自己的实现,接口,但我包括HttpServletRequest的作为全局变量和我使用的HttpServletRequest的方法/ s的实现接口的方法:
public class HttpServletRequestParameterSource implements ParameterSource {
private HttpServletRequest request;
public HttpServletRequestParameterSource(HttpServletRequest request) {
this.request = request;
}
public String[] getParameters(String name) {
return request.getParameterValues(name);
}
}
直到此时,我认为所有的修改上生产守则是安全的。 现在我在我的测试包中创建Seam。如果我理解的很好,现在我能够安全地改变煤层的性能。这就是我要做的事:
public class FakeParameterSource implements ParameterSource {
public String[] values = {"ParamA","ParamB","ParamC"};
public String[] getParameters(String name) {
return values;
}
}
最后的一步,将是来自Seam获得支持,测试方法的原始behavoir。
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import code.ABitOfLegacyRefactored;
import static org.hamcrest.Matchers.*;
public class ABitOfLegacySpecification {
private ABitOfLegacy aBitOfLegacy;
private String EMPTY = null;
@Before
public void initialize() {
aBitOfLegacy = new ABitOfLegacy();
}
@Test
public void
the_output_gets_populated_when_the_request_is_not_empty
() {
FakeParameterSource fakeParameterSource = new FakeParameterSource();
aBitOfLegacy.doSomeProcessing(fakeParameterSource);
assertThat(aBitOfLegacy.output,not(EMPTY));
}
@Test(expected=NullPointerException.class)
public void
should_throw_an_exception_if_the_request_is_null
() {
aBitOfLegacy.doSomeProcessing(null);
}
}
这会给我100%的测试覆盖率。 我很欣赏你的想法:
- 我是否正确地打破了依赖关系?
- 单元测试是否遗漏了一些东西?
- 有什么可以做得更好?
- 这个例子足以帮助我理解Seam和Mock之间的区别吗?
- 如果我不使用Seam,模拟器如何帮助我?
嘲笑不是煤层的替代品。 – Gishu 2013-03-11 10:23:38
你应该拿到那本书并阅读它。 – 2013-03-11 11:19:02