避免仅用于测试目的的无效构造函数 - 允许模拟对象方法抛出异常

时间:2015-07-03 09:40:48

标签: java unit-testing constructor mocking

我想测试一个类的方法。这个类有1个带3个参数的构造函数,我只能提供3个参数中的一个。

我无法模拟对象,因为我正在测试无效使用,所以我需要测试才能获得异常。模拟对象会导致抛出异常。

模仿的问题

public class NodeHandler {
    private List<Node> nodes;
    private Node currentNode;

    public NodeHandler(List<Node> nodes, Object obj1, Object obj2) {
        this.nodes = nodes;
        //uses obj1 and obj2; they cannot be null
    }

    public void initCurrentNode() {
        for(Node node : nodes) {
            if(node.canProcess()) {
                currentNode = node;
                return;
            }
        }

        throw new IllegalStateException("No nodes can be processed");
    }
}

我测试的方法仅取决于List<Node> nodes

我自己手动初始化(在测试中),通过反射访问字段并设置值:

public class MyTest {
    private NodeHandler mocked = Mockito.mock(NodeHandler.class);

    @Test(expected = IllegalStateException.class)
    public void testInvalidUsage() throws Exception {
        List<Node> nodes = new ArrayList<>();
        nodes.add(FirstNode.class.newInstance());
        nodes.add(SecondNode.class.newInstance());

        Field field = NodeHandler.class.getDeclaredField("nodes");
        field.setAccessible(true);
        field.set(mocked, nodes);

        try {
            method.invoke(manager);
        } catch (IllegalAccessException | IllegalArgumentException e) {
            throw new InvocationTargetException(e);
        } catch (InvocationTargetException e) {
            throw (IllegalStateException) e.getTargetException();
        }
    }

    public static class FirstNode extends Node {
        public boolean canProcess() { return false; }
        public void process() { }
    }


    public static class SecondNode extends Node {
        public boolean canProcess() { return false; }
        public void process() { }
    }
}

此测试失败,因为它期望IllegalStateException,但不会抛出一个(由于模拟对象)。

令人讨厌的解决方法

我可以在NodeHandler中声明一个私有的无效构造函数,将其设置为可访问。这将允许我创建一个对象,其方法可能会抛出异常:

class NodeHandler {
    //...

    private NodeHandler() { }

    //...
}

public class MyTest {
    private NodeHandler manager;

    @Before
    public void init() throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        Constructor<?> constructor = NodeHandler.class.getDeclaredConstructor();
        constructor.setAccessible(true);
        manager = (NodeHandler) constructor.newInstance();
    }

    @Test(expected = IllegalStateException.class)
    public void testInvalidUsage() throws Exception {
        //same as before
    }
}

这给了我想要的结果,但似乎&#34; hackish&#34;。我不希望被要求在我想要测试的每个类中声明一个私有构造函数。

我的问题

如果不强制声明一个私有的nullary构造函数,我怎么能测试一个方法,它希望从一个对象抛出异常而不需要填充该对象的构造函数的所有参数?有没有一种方法可以模拟对象,同时还要考虑方法抛出的异常?

0 个答案:

没有答案