如何在Builder()方法中对使用静态单件工厂的构建器进行单元测试?

时间:2015-05-07 14:57:38

标签: java unit-testing factory builder

我正在尝试对Selenium页面对象API进行单元测试,并且我有一堆构建器类使用static单件工厂class来实例化所需的对象。我无法为我的生活找到一种方法来对构建器build()中的class方法进行单元测试。我如何模拟对象创建'为我的建设者?

public class LoadableBuilder<LoadableT extends ILoadable, BeanT extends ILoadableBean>
    implements ILoadableBuilder<LoadableT, BeanT> {

    /**
     * The ILoadableBean object that specifies all the necessary information to construct an instance of the
     * ILoadable that this LoadableBuilder builds
     */
    private final @Getter @Nonnull BeanT state;

    /**
     * The class that of the ILoadable that this LoadableBuilder builds
     */
    private @Getter @Nullable Class<LoadableT> componentClass;

    public AbstractLoadableBuilder(final BeanT state) {
        this.state = state;
    }

    @Override
    public final @Nonnull LoadableBuilder setComponentClass(final Class<LoadableT> componentClass) {
        this.componentClass = componentClass;
        return this;
    }

    @Override
    public final @Nonnull LoadableBuilder setDriver(final WebDriver driver) {
        getState().setDriver(driver);
        return this;
    }

    @Override
    public final @Nonnull LoadableBuilder setLoadTimeoutInSeconds(final @Nonnegative int loadTimeoutInSeconds) {
        getState().setLoadTimeoutInSeconds(loadTimeoutInSeconds);
        return this;
    }

    @Override
    public @Nonnull LoadableT build() {
        return LoadableFactory.getInstance().create(getState(), componentClass);

    }
}

这是工厂:

public class LoadableFactory {
    private static final class Loader {
        private static final LoadableFactory INSTANCE = new LoadableFactory();
    }

    private LoadableFactory() { }

    public static LoadableFactory getInstance() {
        return Loader.INSTANCE;
    }

    public final<BeanT extends ILoadableBean, LoadableT extends ILoadable> LoadableT create(final BeanT bean, final Class<LoadableT> componentClass) {
        final LoadableT component;

        try {
            final Constructor<LoadableT> ctor = ConstructorUtils.getMatchingAccessibleConstructor(componentClass, bean.getClass());
            component = ctor.newInstance(bean);
        } catch (InstantiationException e) {                
            throw new IllegalArgumentException("Could not instantiate an instance of " + componentClass + because it is abstract or an interface or for some other reason.");
        } catch (InvocationTargetException e) {
            throw new IllegalStateException("Could not instantiate an instance of " + componentClass + " because the constructor threw an exception. Cause: " + e.getCause() +". " + e.getMessage());
        } catch (IllegalAccessException e) {
            throw log.throwing(new IllegalArgumentException("Could not instantiate an instance of " + componentClass + " LoadableFactory does not have access to its class definition");
        }
    }
}

1 个答案:

答案 0 :(得分:1)

我不确定这是否是最佳做法,但我过去处理此类问题的方法是将getInstance()调用移至另一个受保护的方法,然后在我的测试类中重写它。您需要让LoadableFactory实现一个模拟create()调用的接口:

protected ILoadableFactory getFactory(){
    return LoadableFactory.getInstance();
}

然后更改您的LoadableBuilder课程以改为使用此代码:

@Override
public @Nonnull LoadableT build() {
    return getFactory().create(getState(), componentClass);
}

然后,在LoadableBuilderTest课程中:

public class LoadableBuilderTest extends LoadableBuilder {
    Mockery context = new Mockery();
    final LoadableFactory mockFactory = context.mock(ILoadableFactory.class); //This is the interface you'll need to make which LoadableFactory implements. It will need the create() method.

    @Override
    protected ILoadableFactory getFactory(){
        return mockFactory;
    }

    @Test
    public void shouldCallCreateProperly(){
        context.checking(new Expectations(){{
            oneOf(mockFactory).create(arg1,arg2);
        }});
        //Do your stuff to test that create() was called.
    }
}