如何模拟单件工厂的对象创建?

时间:2015-05-12 14:19:36

标签: java unit-testing powermock powermockito

我试图遵循的例子:

@PrepareForTest(X.class)
public class XTest extends PowerMockTestCase {
        @Test
        public void test() {
                whenNew(MyClass.class).withNoArguments().thenThrow(new IOException("error message"));

                X x = new X();
                x.y(); // y is the method doing "new MyClass()"

                ..
        }
}

我正在尝试进行单元测试的工厂类:

public final class LoadableBeanFactory implements ILoadableBeanFactory {
    private static final class Loader {
        private static final LoadableBeanFactory INSTANCE = new LoadableBeanFactory();
    }

    private LoadableBeanFactory() { }

    public static @Nonnull LoadableBeanFactory getInstance() {
        return Loader.INSTANCE;
    }

    public final @Nonnull <BeanT extends ILoadableBean> BeanT create(final Class<BeanT> beanClass) {

       final BeanT optionBean;

        try {

            final Constructor<BeanT> ctor = beanClass.getConstructor();
            optionBean = ctor.newInstance();
            return beanClass.cast(optionBean);
        } catch(Exception e) {
           throw new IllegalArgumentException("Could not instantiate an instance of " + beanClass);
        }
    }
}

我的测试如下。工厂没有退回模拟。我认为这是因为工厂是一个单例,它被实例化并加载了一个私有的静态加载器类。那么,有没有办法模拟这个对象创建场景,还是我应该放弃将它变成真正的单元测试?

@PrepareForTest(LoadableBeanFactory.class)
@Test(groups = {"FactoryTestGroup", "LoadableBeanFactoryTestGroup"})
public class LoadableBeanFactoryTest extends PowerMockTestCase {

    @Mock LoadableBean mockBean;

    public void setUp() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void shouldCreateBean() {
        try {

                PowerMockito.whenNew(LoadableBean.class).withNoArguments().thenReturn(mockBean);
            LoadableBeanFactory.getInstance().create(LoadableBean.class);
        assertEquals(LoadableBeanFactory.getInstance().create(LoadableBean.class), mockBean,
                    "LoadableBeanFactory should have return mocked bean, but did not: " + mockBean);
        } catch(Exception e) {
            fail("Failed to mock bean creation");
        }
    }
}

1 个答案:

答案 0 :(得分:1)

为什么你甚至想要这样做?

如果你将工厂包装在一个抽象(一个单独的类)中,那么你可以通过构造函数注入它并模拟它的create方法。

public class BeanFactory {

public <BeanT extends ILoadableBean> BeanT create(final Class<BeanT> beanClass) {
return LoadableBeanFactory.getInstance().create(beanClass);
    }

}

现在您想要使用的课程

public class SomeClass {
private final BeanFactory beanFactory;

public SomeClass(BeanFactory beanFactory)  {
this.beanFactory= beanFactory;
}

public void doSth() {
beanFactory.create(...);
}

}

然后你根本不需要PowerMock,你的设计非常好。