Erlang에서 의존성 주입 및 모의를 어떻게합니까?
-
05-07-2019 - |
문제
Java에서 코드를 작성할 때 수용하는 것이 매우 도움이됩니다. 구성 그리고 의존성 주입 공동 작업을 조롱하여 순수한 장치 테스트를 가능하고 쉽게 수행 할 수 있도록합니다.
Erlang에서 똑같이하는 것은 덜 간단하고 더러운 코드를 만듭니다.
나는 Erlang을 처음 접했고 Junit, Easymock 및 Java 인터페이스에 중독되어 있기 때문에 그것은 내 잘못 일 것입니다 ...
이 바보 같은 기능이 있다고 가정 해 봅시다.
%% module mymod
handle_announce(Announce) ->
AnnounceDetails = details_db:fetch_details(Announce),
AnnounceStats = stats_db:fetch_stats(Announce),
{AnnounceDetails, AnnounceStats}.
단위 테스트시 mymod
, 나는 그것을 증명하고 싶다 details_db
그리고 stats_db
올바른 매개 변수로 호출되며 리턴 값이 올바르게 사용됩니다. 의 능력 details_db
그리고 stats_db
올바른 값을 생성하는 것은 다른 장소에서 테스트됩니다.
문제를 해결하기 위해 내 코드를 이런 식으로 리팩터링 할 수 있습니다.
%% module mymod
handle_announce(Announce, [DetailsDb, StatsDb]) ->
AnnounceDetails = DetailsDb:fetch_details(Announce),
AnnounceStats = StatsDb:fetch_stats(Announce),
{AnnounceDetails, AnnounceStats}.
이런 식으로 테스트하십시오 (기본적으로 통화를 테스트 모듈에 직접 스터브합니다) :
%% module mymod_test
handle_announce_test() ->
R = mymod:handle_announce({announce, a_value}, [?MODULE, ?MODULE, ?MODULE]),
?assertEqual({details,stats}, R).
fetch_details({announce, a_value}) ->
details.
fetch_stats({announce, a_value}) ->
stats.
작동하지만 응용 프로그램 코드가 더러워지고 항상 그 추악한 모듈 목록을 가지고 다니야합니다.
나는 두 개의 모의 라이브러리를 시도했다 (Erlymock 그리고 (이것은 다른 하나입니다)하지만 나는 만족하지 않았다.
Erlang 코드를 어떻게 테스트합니까?
감사!
해결책
여기서 고려해야 할 두 가지가 있습니다 ...
모든 코드를 두 가지 유형의 두 가지 유형으로 분리해야합니다. 모듈:
- 순수한 기능 모듈 (일명 부작용 자유 모듈)
- 부작용이있는 모듈
(이에 대해 읽고 가장 일반적인 부작용 인 차이점과 샘플 코드에있는 차이점이 데이터베이스에 쓰는 것임을 이해해야합니다).
순수한 기능인 모듈은 테스트하기 위해 사소합니다. 내보내는 각 함수 (정의 별)는 동일한 값을 넣을 때 항상 동일한 값을 반환합니다. Eunit/Assert Richard Carlsson과 Mickael Remond가 쓴 프레임 워크. Bish-Bash-Bosh, Job 's a good'un ...
핵심은 코드의 약 90%가 순수한 기능 모듈에 있어야한다는 것입니다. 문제를 극적으로 축소시킵니다. (당신은 이것이 당신의 문제를 '해결'하는 것이 아니라 단지 '그것을 줄이는'것일 뿐이라고 생각할 수도 있습니다. 그리고 당신은 대부분 옳을 것입니다 ...)
이 분리를 달성 한 후에는 부작용으로 모듈을 단위 테스트하는 가장 좋은 방법입니다. 표준 테스트 프레임 워크.
우리가하는 방식은 Mock -Objects를 사용하는 것이 아니라 Init_per_Suite 또는 Init_per_test 함수에 데이터베이스를로드 한 다음 모듈을 직접 실행하는 것입니다.
가장 좋은 방법은 단위 테스트가 유지하기 어려운 고통이기 때문에 가능한 빨리 시스템 테스트로 바로 이동하는 것입니다. 따라서 시스템 테스트 왕복으로 이동하기에 충분한 단위 테스트가 더 이상 (더 나은 삭제를 더 잘 삭제하지 않습니다. DB 단위는 가능한 빨리 테스트합니다).
다른 팁
나는 Guthrie가 말하는 것을 두 번째합니다. 당신은 당신의 논리를 얼마나 순수한 기능으로 끌어낼 수 있는지에 놀랄 것입니다.
최근에 새로운 매개 변수화 된 모듈로 묶는 것 중 하나는 종속성 주입에 매개 변수화 된 모듈을 사용하는 것입니다. 매개 변수 목록 및 프로세스 사전의 문제를 피합니다. 최근 버전의 Erlang을 사용할 수 있다면 적합 할 수 있습니다.
Gordon은 주요 목표는 작은 부작용 자유 함수를 테스트하는 것입니다.
그러나 ... 음, 통합을 테스트 할 수 있으므로 어떻게 할 수 있는지 보여줍니다.
주입
매개 변수화 된 종속성을 전달할 목록을 피하십시오. 레코드, 프로세스 사전, 매개 변수화 된 모듈을 사용하십시오. 코드는 덜 못 생겼습니다.
이음새
의존성 이음새로 가변 모듈에 초점을 맞추지 말고 프로세스가 이음새가되도록하십시오. 등록 된 프로세스 이름을 하드 코딩하는 것은 종속성을 주입 할 수있는 기회가 손실됩니다.
나는 단지 질문에 직접 묻는 질문에 대답하고 있으며 저자가 이것을 전혀 해야하는지 판단하려고하지 않습니다.
사용 메이크 다음과 같이 예제에 대한 단위 테스트를 작성할 수 있습니다.
handle_announce_test() ->
%% Given
meck:new([details_db, stats_db]),
meck:expect(details_db, fetch_details, ["Announce"], "AnnounceDetails"),
meck:expect(stats_db, fetch_stats, ["Announce"], "AnnounceStats"),
%% When
Result = handle_announce("Announce"),
%% Then
?assertMatch({"AnnounceDetails", "AnnounceStats"}, Result),
%% Cleanup
meck:unload().
나는 문자열을 사용하여 실제로 전달되는 것이 아니라 가짜 가치라는 점을 강조합니다. 구문 하이라이트 덕분에 테스트 코드에서 쉽게 찾을 수 있습니다.
솔직히 말해서 나는 전직 자바 개발자입니다. 모키토 최근에 Erlang으로 전환했으며 현재 위에서 언급 한 프로젝트에 기여했습니다.