Effective Java Item 03

Date:

private 생성자나 열거 타입으로 싱글톤임을 보증하라

싱글톤 인스턴스를 가짜 구현으로 대체하기 힘들다.

1. 생성자가 private이기 때문에 상속할 수 없고 테스트에서 싱글톤 인스턴스의 생성을 통제할 수 없다.

2. getInstance 메소드의 경우 static 이기 때문에 가짜 객체를 싱글톤 대신 주입하기 힘들다.

mocking frameworks는 상속(Inheritance)과 다형성(polymorphism)을 기반으로 하고 있는데 2가지 모두 문제가 된다.
사실 다형성이 왜 문제가 되는지는 아직 이해가 안된다...
setter 메소드를 추가해서 테스트 가능하게 하거나 interception과 AOP concept에 기반한 최신 mocking framework 를 이용하는 방법이 있겠다.
PowerMock 을 쓰는 것도 하나의 방법이다.
(PowerMock을 쓰면 일반적으로 mocking이 힘든 static, fianl, private 메소드 mocking이 가능하다)

여기서는 인터페이스를 구현하는 싱글톤에 대해서 자세히 알아보자.

interface Singleton {
    private static final myInstance;
    public static Singleton getInstance() { return myInstance; }
    public static void setInstance(Singleton newInstance) { myInstance = newInstance; }
    // public method declarations
}

// Used in production
class RealSingleton implements Singleton {
    // public methods
}

// Used in unit tests
class FakeSingleton implements Singleton {
    // public methods
}

class ClientTest {
    private Singleton testSingleton = new FakeSingleton();
    @Test
    public void test() {
        Singleton.setSingleton(testSingleton);
        client.doSomething();
        // ...
    }
}

위 코드는 ‘Working Effectively With Legacy Code’책에서 “Introduce Static Setter”라고 불리는 방법이다.

인터페이스를 구현하면 다음과 같은 관점에서도 테스트하기 용이하다.

이런 코드 대신에

void foo() {
   Bar bar = Bar.getInstance();
   // etc...
}

인터페이스를 구현하면 이렇게 쓸 수 있다.

void foo(IBar bar) {
   // etc...
}

가짜 bar 객체를 통해서 foo 메소드를 테스트할 수 있게 된것이다. 다시 말하면, 의존성을 제거해서 bar를 테스트 하지 않고 foo를 테스트 할 수 있게 된 것이다.


참고(Reference)
mocking-a-singleton-class
advantage-of-singleton-implementing-an-interface
why-doesnt-mockito-mock-static-methods
static method와 Override hiding 대한 정리
static method를 mocking 하기
스태틱 클래스 테스트하기

댓글