개인적으로 작업했던 프로젝트는 기존에 unittest
를 이용해서 작성했다. 하지만 다음과 같은 이유로 인해 새로 작성하는 테스트는 pytest
를 이용해 작성했다.
unittest
의 문법은 pep 규약과 잘 맞지 않는다. self.assertEqual(lhs, rhs)
같은 경우는 메서드 이름을 스네이크 케이스로 짓는 pep와 합치하지 않는다.assert
를 기억하고 사용하기에 번거로움이 있다. 반면 pytest
는 단순히 assert
만을 사용하면 되므로 편리하다.하지만 기존 코드베이스에 unittest
를 사용해 작성한 테스트가 상당히 많아 옛날 코드베이스는 그대로 놔두었다.
그런데 얼마 전에 나쁜 코드의 문제는 마치 중력처럼 다른 코드들도 나쁘게 만든다는데 있다는 걸 깨달았다. 새로 온 팀원은 아무래도 기존 코드베이스를 참고해서 작업하게 된다. 우연히 그 팀원이 기존에 unittest
로 작성한 부분을 참고해 self.assertEqual
로 도배한 테스트코드를 작성한 것이다. 물론 코드리뷰 과정을 통해 pytest
로 전환하기는 했지만 서로에게 불필요한 시간낭비였고 기존 코드베이스를 이대로 놔둘 수 없겠다는 생각이 들었다.
이제 고치기로 마음을 먹었지만, 단순히 손으로 고치기에는 양이 좀 많고 사실 머리를 쓸 일은 아닌 거 같았다. 그래서 정규식과 sed
를 활용해 코드베이스를 고치기로 했다.
예시를 보자.
get = self.client.get("/posts")
self.assertEqual(get.status_code, 200)
위 코드는 pytest
를 이용하면 다음과 같이 번역할 수 있다.
assert get.status_code == 200
즉, self.assertEqual(a, b)
는 assert a == b
처럼 번역할 수 있는 것이다. 이제 이걸 sed 문법에 맞게 쓰면 다음과 같이 할 수 있다.
sed -i '' 's/self\.assertEqual(\([^,]*\), \([^)]*\))/assert \1 == \2/' <filename>;
현재 프로젝트의 테스트는 모두 tests/
디렉토리 아래에서 관리하고 있다. 따라서 for loop를 이용해 다음과 같이 반복했다.
for test in $(find tests); do
sed -i '' 's/self\.assertEqual(\([^,]*\), \([^)]*\))/assert \1 == \2/' $test;
done
sed -i '' 's/self\.assertNotEqual(\([^,]*\), \([^)]*\))/assert \1 != \2/' $test;
assertNotEqual
은 위와 같이 할 수 있다.
sed -i '' 's/self\.assertTrue(\([^,]*\))/assert \1/'
이제 unitest
의 matcher들을 pytest
의 matcher들로 모두 바꾸었다. 다시 코드를 보니 눈에 조금 밟히는 것이 있다.
assert get.status_code == 200
위 코드는 다음과 같이 바꾸면 좀 더 의미를 담아낼 수 있다.
from rest_framework import status
assert get.status_code == status.HTTP_200_OK
위 변경은 단순히 텍스트 대치이므로 쉽게 할 수 있다.