Thief of Wealth

이 글을 이해하기 위해서는 2가지 개념이 필요하다.

제목에서 알 수 있듯이 “싱글톤 패턴”, “유닛테스트”이다.

싱글톤 패턴이란?

싱글톤 패턴은 어떤 class가 오직 하나의 instance만 가지도록 하는 패턴이다.

유닛테스트란?

테스트의 한 종류로, 코드의 특정모듈이 의도된 대로 정확히 작동하는지를 검증하는 테스트이다.

싱글톤 패턴과 유닛테스트는 창과 방패의 싸움이다.

많은 테스트 프레임워크가 mock 객체를 생성할때 상속에 의존하기 때문에,

싱글톤 클라이언트 코드를 단위 테스트하기가 어려울 수 있다.

예를들어 아래 링크에서는

 

Singleton

Real-World Analogy The government is an excellent example of the Singleton pattern. A country can have only one official government. Regardless of the personal identities of the individuals who form governments, the title, “The Government of X”, is a g

refactoring.guru

싱글톤 클래스의 생성자는 비공개이고, 대부분의 언어에서 정적 메서드를 재정의하는 것이 불가능하기 때문에
싱글톤을 테스트하기 위한 창의적인 방법을 생각해야한다. 
아니면 그냥 테스트를 작성하지 마라. 또는 싱글톤 패턴을 사용하지마라.

는 문구가 나온다. 왜 그럴까?

사실 이 부분은 직접 경험해보면, 쉽게 이해할 수 있다.

class MySocket {
	static singletonInstance: MySocket | null = null;
	socket: WebSocket | null;

	private constructor(url: string) {
		this.url = url;
	}

	static getInstance(url: string) {
		if(MySocket.singletonInstance === null) {
			MySocket.singletonInstance = new MySocket(url);
		}

		return MySocket.singletonInstance;
	}
}

위와 같은 웹소켓 객체가 있다고 생각해보자.

전형적인 싱글톤패턴으로 구현되어있다.

그럼 이 class를 모킹만하면 될것같은데, 왜 안된다는걸까?

  1. 각 TC간의 커플링이 발생한다.
    비즈니스 로직으로는 필요하지 않은데, 테스트용으로 로직이 들어가는 것은 정말 코드를 잘 작성한 것일까? 라고 생각해볼필요가 있다.

    각 TC입장에서도 싱글톤 객체는 유일하기 때문이다.
    따라서 각 TC를 수행하고 난 뒤에는, 싱글톤 객체를 초기화해주는 로직이 필요하다. 테스트를 위한 로직이 추가되어야한다는 뜻이다.

  2. jest로 모킹이 어렵다.
    jest로 모킹방법하는 방법은 많다. spyOn 으로 모킹하기도하고, jest.mock관련 메서드를 사용할 수도 있다.
    하지만 본질은 같다. 즉, jest는 일반적으로 모듈, 객체의 일부, 모킹하기도 하고, 함수의 반환값을 모킹한다.

    응? 그럼 class의 메서드도 모킹하면되잖아? 뭐가문제지? 라고 생각할 수 있다.
    하지만, 위 MySocket에 대해 테스트코드를 작성하려는 사람은 알것이다.
    테스트코드가 뇌절상태가된다는 것을...

    결국에 불가능한건 없지만, 이 과정은 테스트코드를 작성하는 여러분과 그 테스트코드를 리뷰할 동료와 미래의 나를 괴롭히는 창의적인 수단이 될것이라고 확신한다.

    이유는 객체의 프로토타입이 가진 메서드를 모킹해야, 겨우 테스트가 이론상으로 가능해지는데,
    javascript에서 class 메서드들은 prototype에 저장되기 때문에, prototype에 있는 메서드를 모킹해야하기 때문이다.
    (즉, spyon(MySocket, "getInstance") 이런식으로 모킹하려고하면 실패한다)

    이 글을보고 창의적인 방법으로 jest로 prototype을 모킹해서 싱글톤 클래스 테스트에 성공하신분에게는 박수를!

이렇게

 

유닛테스트는 싱글톤 class를 모킹하려고 창처럼 뚫으려하고,

싱글톤은 자기의 정체성을 지키기위해 외부로부터의 모킹/오버라이딩을 막고 있다.

 

그것을 가능하게 하는 과정에 드는 비용은... 테스트코드를 짰을때 얻을 수 있는 비용보다 과연 높을까?

라는 의문을 가지게하기 충분할것이다.

 

이렇듯 싱글톤과 유닛테스트는 위와같은 한계로, 서로 사랑하기엔 수많은 갈등이 필요한 관계인 것이다. 😞

profile on loading

Loading...