[일반팁] 간단한 팁 - Static 함수를 사용하는 클라스 테스트

Static 함수를 사용하는 클라스 유닛 테스트 하기

오래전에 작성된 프로그램들을 보면 항상 Static 함수의 사용이 많습니다. Function을 사용하자니 OOP가 아닌거 같고 Class로 사용하자니 좀 애매하고 해서 Static을 사용하다보니 모든 코드가 엉켜버리고 Static을 사용하게 돼서 테스트가 어려워져버린 시스템들이 많습니다.

다른 팀에서 일하는 동료가 현재 운영 중인 프로젝트는 Static 함수들의 사용이 너무 많아서 유닛 테스트가 불가능하다는 이야기를 했습니다.

예제를 하나 달라고 하니 아래 같은 아주 간단한 클라스 (?)를 줬습니다.

class Cookie
{
    public static function set($name, $value)
    {
        setcookie($name, $value);
    }

    public static function get($name)
    {   
        if (isset($_COOKIE[$name])) {
            return $_COOKIE[$name];
        }

        return null;
    }
}

가장 큰 문제가 PHP 내장 함수인 setcookie를 사용하면 phpunit 실행할 때 header가 먼저 보내지기 때문에 에러가 납니다.

상황이 이러면 선택을 해야 합니다.

  1. 해당 클라스 리팩토링 + 해당 클라스 사용하는 클라스들 모두 리팩토링
  2. 리팩토링이 계획에 없다면 해당 클라스 사용 그대로 유지하면서 테스트

대부분의 오래된 코드는 현재 기준으로 리팩토링을 하면 사실 리팩토링이 아니라 전부 새로 코딩이라 일반적으로 2번을 선택합니다.

테스트 책을 보신 분들은 아시겠지만 2번의 경우 해결 방법이 의외로 쉽습니다. setMock() static 함수를 추가하고 set과 get이 불려질때 체크해서 값이 있으면 해당 Mock 클라스를 호출하면 됩니다.

<?php

class Cookie
{
    private static $mock;

    public static function set($name, $value) 
    {
        if (static::$mock) {
            return static::$mock->set($name, $value);
        }

        setcookie($name, $value);
    }

    public static function get($name) {
        if (static::$mock) {
            return static::$mock->get($name);
        }

        if (isset($_COOKIE[$name])) {
            return $_COOKIE[$name];
        }

        return null;
    }

    public static setMock(aMockClass $mock)
    {
        static::$mock = $mock;
    }
}

aMockClass는 따로 만드셔도 되고 아니면 Mockery 같은 Mocking 라이브러리를 사용하셔도 됩니다. 실질적으로 테스트 할 때는 테스트 셋업 함수에서 Cookie::setMock() 호출하시면 setcookie의 영향 없이 테스트할 수 있습니다.

comments powered by Disqus