MySQL 트랜젝션은 auto_increment 값을 되돌리지 않음

라라벨 애플리케이션에서 아래와 같은 테스트를 작성했습니다. 이해를 돕기 위해 구체적인 내용은 생략했습니다.

use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;

class SampleTest extends TestCase
{
    use RefreshDatabase;

    testFirst()
    {
        //테이블 A에 데이터 10개 추가
        //테스트 수행
    }

    testSecond()
    {
        //테이블 A에 데이터 11개 추가
        //테이블 A에서 데이터 10개를 ID 역순으로 조회 후, 10번째의 데이터의 ID가 값을 확인하는 테스트
    }
}

RefreshDatabase 트레이트를 사용했기 때문에 testSecond 테스트에서 ID는 2가 될 것으로 예상했습니다. 하지만 12가 나와서 테스트를 통과하지 못하더군요.

처음에는 RefreshDatabase의 트랜젝션이 동작하지 않는다고 의심했는데, 알고보니 트랜젝션이 auto_increment 값은 되돌리지 않았기 때문이었습니다.

이전 테스트가 다음 테스트에 영향을 미치지 않아야하지 않나 생각하는데, RefreshDatabase를 쓸 때는 auto_increment 값은 롤백되지 않는다는 점에 주의해서 테스트 코드를 작성해야겠습니다.

Mockery::close() 가 예외를 발생시키면 DatabaseTransactions 트레이트가 동작하지 않음

메소드 하나만 테스트 돌렸을 땐 통과되던게, 파일을 통으로 돌리니까 에러가 나더군요.

에러가 나는 원인을 보니, 데이터베이스에서 락이 걸렸기 때문이었습니다.

DatabaseTransactions 트레이트를 쓰고 있어서, 이전 테스트가 다음 테스트에 영향을 줄 이유가 전혀 없어보이는데, 대체 락이 왜 걸릴까? 찾다보니 원인은 Mockery 때문이었습니다. 이 링크 덕분에 알게 됐어요.  이 글 없었으면 며칠 날릴뻔 했네요. 소중한 정보 공유해준 얼굴 모를 개발자에게 오늘도 감사를!

Mockery를 쓰려고 했다가 필요 없어져서 테스트 코드에서는 Mockery 쓰는 부분을 다 제거했는데, 종료하는 코드를 남겨뒀더라구요.

public function tearDown() {
    Mockery::close();
}

종료할 Mockery가 없는데 종료를 해서 예외가 발생했었나봅니다. Mockery가 예외를 발생시키면, 트랜젝션이 롤백되지 않은채로 테스트가 멈추기 때문에 락이 걸린 채로 다음 테스트가 실행되나 봅니다.

위 코드를 제거하고 돌리니 잘 되네요.

오늘의 삽질 로그 끝