DSA 프로젝트에서 is_feasible()과 bid()를 분리해두고 나니, 이제 조건 하나를 수정하거나 새로 추가할 때마다 원래 잘 되던 다른 조건까지 같이 망가질까 계속 신경 쓰였다. 배터리 여유분(SAFE_SOC_RESERVE) 계산 방식을 바꿨는데, 그 김에 센서 불가 판단이나 마감 시간 판단까지 조용히 깨져버리면 알아채기 어렵다. 이걸 확인하는 절차로 regression test(회귀 테스트)가 있다고 해서 정리해본다.
회귀 테스트란 코드를 변경(버그 수정, 리팩토링, 기능 추가)한 뒤에도 이전까지 잘 동작하던 기능이 여전히 잘 동작하는지 확인하는 테스트다.
회귀(regression)는 한 번 고쳐졌거나 잘 동작하던 것이 코드 변경으로 인해 다시 원래의 나쁜 상태로 되돌아가는 것으로, 기존에 이미 검증된 동작들이 이번 변경으로 깨지지 않았는지를 보는 테스트다.
regression test를 어떻게 수행할지에 대해 몇 가지 접근이 있다.
(위키피디아 - Regression testing)
지금 프로젝트는 아직 MVP 초반 단계라 테스트 스위트 자체가 크지 않다. tests/test_models.py에 있는 테스트를 전부 돌려도 이 정도다.
$ pytest tests/ -q
............ [100%]
12 passed in 0.03s
12개 테스트가 0.03초에 끝나기 때문에, 지금 단계에서는 굳이 일부만 골라 돌리는 selection이나 prioritization을 고민할 이유가 없다. 그래서 현재는 Retest All 방식 그대로, 코드를 한 줄이라도 고치면 전체 스위트를 다시 돌리는 식으로 회귀를 확인하고 있다.
구체적으로는 is_feasible()과 bid()를 나눌 때, 각 조건/공식이 원래 의도한 대로 동작하는지를 아래처럼 테스트로 고정해뒀다.
def test_infeasible_when_sensor_unavailable():
sc, task = _base_feasible_pair()
sc.sensor_availability = False
assert is_feasible(sc, task, current_time=0.0) is False
def test_bid_increases_with_priority():
sc = _make_spacecraft()
low = _make_task(priority=1.0)
high = _make_task(priority=10.0)
assert bid(sc, high) > bid(sc, low)
이렇게 해두면, 나중에 예를 들어 _battery_margin() 계산식을 고치거나 is_feasible()에 통신 링크 조건을 추가하더라도, 전체 테스트를 한 번 돌려서 test_infeasible_when_sensor_unavailable이나 test_bid_increases_with_priority 같은 기존 테스트가 여전히 통과하는지만 확인하면 된다. 통과하면 "이번 변경이 기존 동작을 회귀시키지 않았다"는 게 보장되고, 실패하면 그 지점에서 뭘 건드렸는지 바로 알 수 있다.
프로젝트가 커져서(예: CBBA 단계로 가서 스케줄 인식 bid나 라운드 기반 합의 로직이 추가되면) 테스트 수가 늘고 실행 시간도 길어질 텐데, 그때는 변경된 모듈과 관련된 테스트만 골라 돌리는 selection이나, 실패 가능성이 높은 테스트부터 먼저 돌리는 prioritization을 고려해볼 것 같다.