Java 如何使用JUnit和JMock测试抽象类的受保护方法

Java 如何使用JUnit和JMock测试抽象类的受保护方法,java,unit-testing,junit,jmock,Java,Unit Testing,Junit,Jmock,我有这样的情况——我有接口(比如说MyInterface)和简单的部分实现(AbstractMyInterface)。后者添加了一些我想测试的受保护方法 目前,我只是手工编写一个mock对象,它扩展了AbstractMyInterface,并将受保护的方法导出为public。有没有一种更简单的方法可以做到这一点——例如使用JMock+脚本?我看不出用JUnit测试受保护的方法有任何问题。只要测试的包结构镜像源树结构,测试就可以看到私有以外的方法 当然,若要测试的实现是抽象的,那个么您必须自己创建

我有这样的情况——我有接口(比如说
MyInterface
)和简单的部分实现(
AbstractMyInterface
)。后者添加了一些我想测试的受保护方法


目前,我只是手工编写一个mock对象,它扩展了
AbstractMyInterface
,并将受保护的方法导出为public。有没有一种更简单的方法可以做到这一点——例如使用JMock+脚本?

我看不出用JUnit测试受保护的方法有任何问题。只要测试的包结构镜像源树结构,测试就可以看到私有以外的方法

当然,若要测试的实现是抽象的,那个么您必须自己创建被测试类的普通子类(或者,若更适合您的目的,可以通过一些模拟库来创建)。同样在这种情况下,不需要为调用受保护的可见性方法创建公共方法层。仅对于私有方法,此策略不起作用。但通常需要测试私有方法是设计问题的标志

例如: 要测试的类位于src/mypackage/AbstractClass.java 包我的包

/** This could as well implement some interface, 
    but that does not change a thing */
public abstract class AbstractClass {
    protected int returnsOne() {
        return 1;
    }
}
和位于tests/mypackage/AbstractClassTest.java的test

package mypackage;

import org.junit.Test;

import static junit.framework.Assert.assertEquals;

public class AbstractClassTest {
    @Test
    public void returnsOneReturnsOne() {
        AbstractClass instanceToTest = new AbstractClassTestable();
        assertEquals(1, instanceToTest.returnsOne());
    }
}

/** This is needed, because we cannot construct abstract class directly */
class AbstractClassTestable extends AbstractClass {
}

您可以为接口(或抽象类)创建抽象测试用例。然后为接口(或抽象类)的每个具体实现创建一个具体的测试用例,扩展抽象测试用例。

只是一个建议

如果我们不测试受保护的方法,我们可以使用公共方法覆盖这些受保护的方法吗

如果不是,是因为受保护的方法过于复杂,重构以将复杂的内容提取到新对象,该对象提供公共接口,而旧对象在某些公共方法中仅保留一个私有对象

稍后将对新对象进行测试


这可能会有帮助。

除了我在测试中有越来越多的未使用存根之外,没有问题。在您的代码片段中,我认为您忘记了向您的AbstractClass:)添加
abstract
修饰符,而不是使用内部类,您可以简单地将
instanceToTest
初始化为
new AbstractClass(){}否-受保护的方法非常简单,但它们被整合到公共API(简单发布/订阅模型的一部分)中。该部件由公共方法使用,但为了测试它是否工作,我需要访问受保护的部件。虽然我同意私有方法不应该被测试,但是受保护的方法被其他人使用。公共方法需要访问由受保护的方法包装的公共API,看起来这个类有两个任务。设计一个包装器类来隐藏公共API,并设计一个用户类来使用包装器提供的服务。因此,即使API要更改,也不会对可能充满逻辑的用户类造成伤害。我从为凌乱的十年生命周期的c代码进行单元测试中学到的是,如果很难进行单元测试,那么离开它,重构代码是一种简单而好的RoI方法。Chris Zheng:对于使用发布-订阅的简单代码,你能证明这一点吗?公共方法应该只注册/取消注册观察者,而受保护的方法只触发各种事件(在观察者设置和发送通知事件上循环)。我看不到解决方案,它可以按照你们描述的方式来做,并且不会违反接吻规则。好的,我明白了。如果这就是您所拥有的,那么创建一个新类似乎并不简单。但它非常简单,可以通过公共接口进行测试。模拟此对象,并通过公共接口进行测试,检查是否发送了通知事件。