被测单位:Impl或Interface? [英] Unit under test: Impl or Interface?

查看:114
本文介绍了被测单位:Impl或Interface?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有实现它的接口和实现类,我想为此写单元测试。我应该测试接口或Impl?



这是一个例子:

  public interface HelloInterface {
public void sayHello();
}


public class HelloInterfaceImpl实现HelloInterface {
private PrintStream target = System.out;


@Override
public void sayHello(){
target.print(Hello World);



public void setTarget(PrintStream target){
this.target = target;
}
}

所以,我有HelloInterface和HelloInterfaceImpl来实现它。什么是单元下测试接口或Impl?



我认为应该是HelloInterface。考虑下面的JUnit测试草图:

  public class HelloInterfaceTest {
private HelloInterface hi;

@Before
public void setUp(){
hi = new HelloInterfaceImpl();
}

@Test
public void testDefaultBehaviourEndsNormally(){
hi.sayHello();
// no NullPointerException here
}

@Test
public void testCheckHelloWorld()throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
PrintStream target = new PrintStream(out);
PrivilegedAccessor.setValue(target,target);
//你可以使用ReflectionTestUtils代替PrivilegedAccessor
//真的是DI
//((HelloInterfaceImpl)hi).setTarget(target);
hi.sayHello();
String result = out.toString();
assertEquals(Hello World,result);

}
}

主线实际上是我评论了



((HelloInterfaceImpl)hi).setTarget(target);



方法 setTarget()不是我的公共接口的一部分,所以我不想意外调用它。如果我真的想叫它,我应该花一点时间思考一下。例如,它可以帮助我发现我真正想要做的是依赖注入。为我开启了全球新机遇。我可以使用一些现有的依赖注入机制(例如Spring的),我可以像我在代码中做的那样自己模拟它,或者采取完全不同的方法。仔细看看,PrintSream的准备不是那么容易,也许我应该使用模拟对象吗?



编辑
我想我应该永远关注界面。从我的角度来看, setTarget()不是impl类的contract的一部分,它也不适用于依赖注入。我认为,从测试的角度来看,Impl类的任何公共方法都应该被视为私有的。这并不意味着我忽略了实现细节。



另请参见私人/受保护的方法是否在单元测试之下?



编辑-2 在多个实现的情况下,多个接口,我将测试所有的实现,但是当我在 setUp()方法中声明一个变量我一定会使用界面。

解决方案

实现是需要测试的单元。这当然是你正在实例化的,包含程序/业务逻辑的东西。



如果你有一个关键的界面,而且你想确保每个实现都遵守它那么你可以编写一个专注于接口的测试套件,并要求一个实例被传递(不管是任何实现类型)。



是的,这可能会更容易要将Mockito用于PrintStream,可能并不总是可以避免使用像这样的具体示例中的模拟对象。


Suppose I have interface and implementation class that implements it and I want to write unit-test for this. What should I test interface or Impl?

Here is an example:

public interface HelloInterface {
    public void sayHello();
}


public class HelloInterfaceImpl implements HelloInterface {
    private PrintStream target = System.out;


    @Override
    public void sayHello() {
        target.print("Hello World");

    }

    public void setTarget(PrintStream target){
        this.target = target;
    }
}

So, I have HelloInterface and HelloInterfaceImpl that implements it. What is unit-under-test interface or Impl?

I think it should be HelloInterface. Consider following sketch of JUnit test:

public class HelloInterfaceTest {
    private HelloInterface hi;

    @Before
    public void setUp() {
        hi = new HelloInterfaceImpl();
    }

    @Test
    public void testDefaultBehaviourEndsNormally() {
        hi.sayHello();
        // no NullPointerException here
    }

    @Test
    public void testCheckHelloWorld() throws Exception {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        PrintStream target = new PrintStream(out);
        PrivilegedAccessor.setValue(hi, "target", target);
        //You can use ReflectionTestUtils in place of PrivilegedAccessor
        //really it is DI 
        //((HelloInterfaceImpl)hi).setTarget(target);
        hi.sayHello();
        String result = out.toString();
        assertEquals("Hello World", result);

    }
 }

The main line is actually one that I commented out.

((HelloInterfaceImpl)hi).setTarget(target);

Method setTarget() is not part of my public interface, so I don't want to accidentally call it. If I really want to call it, I should take a moment and think about it. It helps me, for example, to discover that what I'm really trying to do is dependency injection. It opens for me the whole world of new opportunities. I can use some existing dependency injection mechanism (Spring's, for example), I can simulate it myself as I actually did in my code or to take totally different approach. Take a closer look, preparation of PrintSream wasn't that easy, maybe I should use mock object instead?

EDIT: I think I should always focus on the interface. From my point of view setTarget() is not part of the "contract" of the impl class neither, it serves sally for dependency injection. I think any public method of Impl class should be considered as private from the testing perspective. It doesn't mean that I ignore the implementation details, though.

See also Should Private/Protected methods be under unit test?

EDIT-2 In the case of multiple implementations\multiple interfaces, I would test all of the implementations, but when I declare a variable in my setUp() method I would definitely use interface.

解决方案

The implementation is the unit that needs to be tested. That is of course what you are instantiating and what contains the program/business logic.

If you had a critical interface and you wanted to make sure every implementation adhered to it properly, then you may write a test suite that focuses on the interface and requires an instance be passed in (agnostic of any implementation type).

Yes, it would probably be easier to use Mockito for PrintStream, it may not always be possible to avoid using a mock object like you did in this specific example.

这篇关于被测单位:Impl或Interface?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆