从特定方法检测或阻止对方法的调用

时间:2014-12-01 00:43:51

标签: java

我正在为提交给竞赛的代码编写JUnit测试。竞赛规则要求某些方法不能从其他方法中调用。 (遗憾的是我不能改变规则。)

参赛者都在实施我们提供的界面,其中包括add(K key, V value)方法和delete(K key)方法。我们需要通过将所有其他元素添加到新对象并返回该对象来测试条目不实现删除。

我们还试图避免在Java核心之外添加依赖项,因为我们使用了大量自动化工具(如Marmoset Project)来测试数百个提交。

我阅读了Java反射和仪器的文档,但没有任何内容突然出现在我身上。

如果它有所作为,我们正在使用Java 8.

3 个答案:

答案 0 :(得分:0)

AspectJ编译时编织可能是你最好的选择。

您需要使用aspectj编译器重新编译代码并添加建议来拦截调用。

如果你给我更多细节,我可以展示一些示例代码。

答案 1 :(得分:0)

您可能想要一个模拟库,并使用"间谍"测试对象。使用Mockito可能看起来像这样。

例如

import static org.mockito.Mockito.*;

public class Test {

    @Spy 
    ClassUnderTest classUnderTest;

    @Before
    public void init() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void deleteNeverCalled() {
        // given
        String key = randomString();
        String value = randomString();

        // when
        classUnderTest.add(key, value)

        // then
        verify(classUnderTest, never()).delete(any());
    }

}

答案 2 :(得分:0)

这是我最终的解决方案。看起来在原始问题中,我没有提到这是一个二叉树,所以compareTo函数会不断使用。

我创建了一个Exception,我们可以在我们的测试框架中抛出然后检测。

public static class NotAllowedException extends RuntimeException

我创建了一个新类型,在调用delete之前,测试框架可以将一个标志设置为true。

/**
 * This class uses reflection to check whether {@link compareTo()} is being
 * called inside the add method after the test decides it is done with the
 * add method.
 * It will throw a {@link NotAllowedException}.
 *
 * @author yakatz <email@domain.com>
 */
private class MyIntWrapper {
    private boolean doneAdding = false;

    public void doneAdding() {
        this.doneAdding(true);
    }

    public void doneAdding(boolean b) {
        this.doneAdding = b;
    }

    private class MyInteger implements Comparable<MyInteger> {

        private Integer value;

        public MyInteger(int value) {
            this.value = value;
        }

        @Override
        public int compareTo(MyInteger o) {
            if (MyIntWrapper.this.doneAdding) {
                StackTraceElement[] causes = Thread.currentThread().getStackTrace();
                for (StackTraceElement cause : causes) {
                    if (cause.getClassName().equals("tree.Node") && cause.getMethodName().equals("add")) {
                        throw new NotAllowedException();
                    }
                }
            }
            return this.value.compareTo(o.value);
        }
    }
}

然后我可以在这样的测试中使用该类:

MyIntWrapper mir = new MyIntWrapper();
Tree<MyIntWrapper.MyInteger, String> tree = new Tree();
// Add stuff to the tree
mir.doneAdding();

MyIntWrapper.MyInteger mi = mir.new MyInteger(1);
tree = tree.delete(mi); // Will throw NotAllowedException if add() is called