PHP 프레임워크 – Symfony – 9 – 유닛 테스트

PHP 프레임워크 - Symfony - 9 - 유닛 테스트
PHP 프레임워크 – Symfony – 9 – 유닛 테스트

PHP 프레임워크 – Symfony – 9 – 유닛 테스트

안녕하세요, 여러분 😊
오늘은 Symfony 프레임워크에서의 **유닛 테스트(Unit Test)**에 대해 알아보는 시간을 가져볼게요!
코드를 작성하면서 “이게 진짜 잘 작동할까?”라는 의문을 가져보신 적 있으시죠?
이럴 때 바로 필요한 것이 테스트랍니다.

유닛 테스트는 **작은 단위(함수, 메서드, 클래스)**를 검증하는 테스트로,
버그를 초기에 잡고 유지보수를 쉽게 해주는 개발자의 방패와 같은 존재예요.
Symfony는 PHPUnit 기반으로 유닛 테스트를 손쉽게 작성할 수 있도록 도와준답니다!


유닛 테스트란 무엇인가요?

유닛(Unit)은 프로그램의 가장 작은 동작 단위를 의미하고,
유닛 테스트는 이 작은 단위가 기대한 대로 동작하는지를 자동으로 확인하는 방법입니다.

🚗 비유하자면, 자동차 공장에서 조립 전 바퀴 하나, 엔진 하나씩 테스트하는 것과 같아요!
전체 시스템을 완성하기 전에 부품 하나하나가 제대로 작동하는지 검증하는 과정입니다.


Symfony에서 유닛 테스트 환경 구성하기

Symfony 프로젝트에서는 기본적으로 PHPUnit을 사용합니다.
설치와 설정도 매우 간단해요!

1. PHPUnit 설치

composer require --dev phpunit/phpunit

Symfony Flex를 사용할 경우 다음 명령으로도 자동 구성됩니다:

composer require --dev symfony/test-pack

✅ 이 명령어는 phpunit.xml.dist 설정 파일과 tests/ 디렉토리를 자동으로 생성해줍니다.


유닛 테스트 기본 구조 이해하기

Symfony에서는 테스트 클래스를 tests/ 디렉토리에 작성합니다.

tests/
├── Controller/
├── Service/
├── Entity/
└── Util/

예시: 간단한 서비스 테스트

// src/Service/Calculator.php
namespace App\Service;

class Calculator
{
    public function add(int $a, int $b): int
    {
        return $a + $b;
    }
}
// tests/Service/CalculatorTest.php
namespace App\Tests\Service;

use App\Service\Calculator;
use PHPUnit\Framework\TestCase;

class CalculatorTest extends TestCase
{
    public function testAdd()
    {
        $calc = new Calculator();
        $this->assertEquals(4, $calc->add(2, 2));
    }
}

📌 TestCase를 상속한 클래스 내에서 test로 시작하는 메서드를 만들고,
assertEquals, assertTrue, assertFalse 등 다양한 검증 메서드를 사용해 테스트합니다.


테스트 실행하기

테스트는 다음 명령어로 실행할 수 있어요:

php bin/phpunit

또는 특정 테스트 파일만 실행하고 싶을 경우:

php bin/phpunit tests/Service/CalculatorTest.php

🎯 결과는 성공, 실패, 오류로 구분되며, 실패한 테스트는 어떤 부분에서 문제가 발생했는지 상세하게 출력됩니다.


Symfony 통합 테스트와 구분하기

Symfony에서는 **유닛 테스트(Unit Test)**뿐 아니라 **통합 테스트(Integration Test)**도 가능해요.

  • 유닛 테스트는 클래스 하나만 독립적으로 테스트
  • 통합 테스트는 여러 컴포넌트가 함께 작동하는지 테스트

유닛 테스트 vs 통합 테스트 비교

항목 유닛 테스트 통합 테스트
대상 클래스, 함수 서비스, 컨트롤러 등 전체 흐름
속도 빠름 상대적으로 느림
목적 내부 로직 검증 시스템 연결성 검증
의존성 없음 또는 Mock 실제 의존 객체 사용

Mock 객체 사용하기

의존성을 제거하고 순수한 로직만 테스트하고 싶을 때는 Mock 객체를 사용해요.

$logger = $this->createMock(LoggerInterface::class);
$logger->expects($this->once())
       ->method('info')
       ->with('로그가 남았습니다!');

이렇게 하면 외부 로그 시스템 없이도 테스트가 가능해집니다.


Entity 유닛 테스트 예제

// src/Entity/User.php
namespace App\Entity;

class User
{
    private $email;

    public function setEmail(string $email)
    {
        $this->email = strtolower($email);
    }

    public function getEmail(): string
    {
        return $this->email;
    }
}
// tests/Entity/UserTest.php
namespace App\Tests\Entity;

use App\Entity\User;
use PHPUnit\Framework\TestCase;

class UserTest extends TestCase
{
    public function testEmailLowercase()
    {
        $user = new User();
        $user->setEmail('TEST@MAIL.COM');
        $this->assertEquals('test@mail.com', $user->getEmail());
    }
}

🧪 위 테스트는 이메일이 소문자로 저장되는지를 검증하고 있어요.


코드 커버리지 확인하기 (Coverage Report)

PHPUnit은 코드 커버리지도 확인할 수 있어요.

php bin/phpunit --coverage-html coverage/

이 명령을 실행하면 coverage/ 폴더에 브라우저로 확인 가능한 HTML 리포트가 생성돼요.
🧭 어떤 코드가 테스트되고 있고, 어디가 누락되었는지를 시각적으로 파악할 수 있어요!


유닛 테스트에서 자주 쓰이는 어서션 함수

메서드 설명
assertEquals(a, b) a와 b가 같은 값인지 확인
assertTrue(cond) 조건이 true인지 확인
assertFalse(cond) 조건이 false인지 확인
assertInstanceOf(cls, obj) 객체가 특정 클래스의 인스턴스인지 확인
assertCount(n, arr) 배열/컬렉션의 요소 개수 확인
assertNull(val) 값이 null인지 확인

유닛 테스트를 작성할 때 주의할 점 ✅

항목 설명
테스트는 독립적으로 서로 영향을 주지 않도록 분리해야 해요
반복 가능한 결과 랜덤이나 시간 의존 로직은 테스트 어려움
외부 의존성 제거 DB나 API 호출은 Mock 객체로 대체
실패 기준을 명확히 기대값과 실제 결과가 어떻게 달랐는지 로그 남기기
적절한 테스트 커버리지 전체 로직 중 핵심 부분은 꼭 테스트하기

마무리하며 😊

Symfony에서 유닛 테스트는 단순히 “버그 잡기”의 도구가 아닙니다.
신뢰할 수 있는 코드, 유지보수하기 쉬운 구조, 팀워크가 쉬운 프로젝트를 만들어주는
개발자의 든든한 안전벨트와도 같아요!

테스트 없이 코딩하는 건 낙하산 없이 하늘을 나는 것과 같다는 말, 들어보셨죠?
조금은 귀찮을 수 있지만, 유닛 테스트는 장기적으로 여러분의 시간과 노력을 아껴주는 최고의 투자입니다.

그럼 다음 시간에는 Symfony에서 이벤트(Event) 시스템과 리스너 구성에 대해 알아보도록 할게요!
오늘도 즐코하시고, 실패 없는 코드를 위하여! 🧪💻✨

답글 남기기