嘲笑单身人士班

嘲笑单身人士班

问题描述:

我最近读到,制作类单例使得无法模拟类的对象,这使得测试其客户端变得困难。我无法立即理解其根本原因。有人可以解释是什么让模拟单身人士课程变得不可能吗?此外,还有更多的问题与制作类单身?

I recently read that making a class singleton makes it impossible to mock the objects of the class, which makes it difficult to test its clients. I could not immediately understand the underlying reason. Can someone please explain what makes it impossible to mock a singleton class? Also, are there any more problems associated with making a class singleton?

当然,我可以写类似不要使用单身,它们是邪恶的,使用Guice / Spring /无论但首先,这不会回答你的问题,其次,你有时必须处理单身,在使用时遗留代码例如。

Of course, I could write something like don't use singleton, they are evil, use Guice/Spring/whatever but first, this wouldn't answer your question and second, you sometimes have to deal with singleton, when using legacy code for example.

所以,我们不讨论单身人士的好坏(还有另一个但是让我们看看在测试过程中如何处理它们。首先,让我们看一下单例的常见实现:

So, let's not discuss the good or bad about singleton (there is another question for this) but let's see how to handle them during testing. First, let's look at a common implementation of the singleton:

public class Singleton {
    private Singleton() { }

    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }

    public String getFoo() {
        return "bar";
    }
}

这里有两个测试问题:


  1. 构造函数是私有的,所以我们无法扩展它(我们无法在测试中控制实例的创建,但是,这是单身人士的观点。)

  1. The constructor is private so we we can't extend it (and we can't control the creation of instances in tests but, well, that's the point of singletons).

getInstance 是静态的,所以很难注入假的单例对象在使用单例的代码中。

The getInstance is static so it's hard to inject a fake instead of the singleton object in the code using the singleton.

对于基于的模拟框架继承和多态,这两点都是明显的大问题。如果您可以控制代码,一个选项是通过添加一个允许调整内部字段的setter使您的单例更易于测试,如学会停止担心和爱单身人士(你甚至不需要一个模拟框架那个案子)。如果不这样做,基于拦截和AOP概念的现代模拟框架可以克服前面提到的问题。

For mocking frameworks based on inheritance and polymorphism, both points are obviously big issues. If you have the control of the code, one option is to make your singleton "more testable" by adding a setter allowing to tweak the internal field as described in Learn to Stop Worrying and Love the Singleton (you don't even need a mocking framework in that case). If you don't, modern mocking frameworks based on interception and AOP concepts allow to overcome the previously mentioned problems.

例如,模拟静态方法调用显示如何使用 JMockit Expectations

另一种选择是使用 PowerMock ,这是对Mockito或JMock的扩展,允许模拟通常不像static,final,private或constructor方法那样的东西。您还可以访问课程的内部。

Another option would be to use PowerMock, an extension to Mockito or JMock which allows to mock stuff normally not mockable like static, final, private or constructor methods. Also you can access the internals of a class.