[Rust] mockall로 테스트 모킹하기

mockall은 인터페이스(trait) 기반의 mock 타입을 자동 생성해주는 보조 라이브러리다.
이게 그나마 좀 사이즈가 있고 많이 쓰는 것 같다.

동작 원리 자체는 복잡할게 없다. 그냥 트레잇에 대해서 mocking용 타입을 자동 생성해주는 정도다.




설치

설치 방법은 간단하다. 디펜던시 하나만 add로 추가해주면 된다.




기본 사용법

mockall을 사용하려면, 먼저 모킹할 대상 기능을 먼저 인터페이스 단위로 추상화를 해야 한다.
인터페이스를 기반으로 generation을 하는 기능이기 때문이다.

그래서 만약 uuid를 생성하는 기능에 대해서 모킹을 하고 싶다면, 이런식으로 trait을 정의해줘야 한다.

그리고 실제 비즈니스 로직에서는 트레잇을 기반으로만 동작하게 해야 한다.
그래야 모킹을 활용한 테스트가 가능해진다.


모킹을 생성하는 방법은 어렵지 않다.
이렇게 매크로만 붙여주면 타입을 자동으로 생성해준다.
자동으로 생성되는 타입은 트레잇 이름 앞에 Mock이 붙는다.


모킹 타입은 이런식으로 생성해서


이렇게 갖다쓸 수 있다.


그리고 모킹 객체로 메서드를 호출하면, 사전에 정의한 expectation에 정의한 리턴값을 반환해준다.

만약, expection에 맞지 않는 호출이 발생하면 mockall은 바로 패닉을 던진다.

한번만 호출할 수 있게 해놨는데 두번 호출해서다.


한 모킹 객체에 대해서 expectation은 원하는 만큼 잔뜩 뽑아낼 수 있다.




파라미터 Match

파라미터를 받는 것은 조금 복잡하게 느껴질 수도 있다.

with절에 전용 predicate 함수들을 사용해서 파라미터를 match해줘야 한다.
저러면 파라미터가 1, 2인 것에 대해서만 올바르게 동작하고


맞지 않다면 에러를 던질 것이다.
여기서 좀 아쉬운 점은 근사한 expectation에 대해서 diff를 보여주지는 않는다는 점이다. 케이스가 방대해지면 그런게 좀 있어야 찾기가 쉬운데 말이다.


만약 항상 일치하는 match를 넣고 싶다면, always를 쓰면 된다.
저러면 뭐가 들어와도 일치하는 걸로 친다.


predicate 함수 목록은 이정도 있다.
https://docs.rs/mockall/latest/mockall/predicate/index.html

predicate 함수를 쓰기 번잡하고 꺼려진다면, 그냥 predicate 클로저를 직접 넣어서 처리하는 방법도 있다.

이런 식이다.




참조
https://blog.logrocket.com/mocking-rust-mockall-alternatives/
https://docs.rs/mockall/latest/mockall/