Mat*_*ari 21 erlang unit-testing dependency-injection mocking
在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}.
Run Code Online (Sandbox Code Playgroud)
在单元测试时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}.
Run Code Online (Sandbox Code Playgroud)
并以这种方式进行测试(基本上将调用直接存入测试模块):
%% 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.
Run Code Online (Sandbox Code Playgroud)
它工作正常,但应用程序代码变脏了,我总是要随身携带那些丑陋的模块列表.
我尝试了几个模拟库(erlymock和(另一个),但我并不满意.
你如何对你的erlang代码进行单元测试?
谢谢!
Gor*_*rie 22
这里要考虑两件事......
您需要将所有代码分成两个不同类型的模块:
(您应该阅读并确保您了解其中的差异 - 最典型的副作用 - 以及示例代码中的副作用 - 正在写入数据库).
纯功能模块变得微不足道.每个导出的函数(根据定义)在放入相同的值时总是返回相同的值.您可以使用Richard Carlsson和Mickael Remond编写的EUnit/Assert框架.Bish-bash-bosh,工作很好'不...
关键是大约90%的代码应该是纯粹的功能模块 - 你会大大减少你的问题.(你可能认为这不是'解决'你的问题,只是'减少'它 - 你会大致正确......)
一旦实现了这种分离,对具有副作用的模块进行单元测试的最佳方法是使用标准测试框架.
我们这样做的方式不是使用模拟对象 - 而是在init_per_suite或init_per_test函数中加载数据库,然后自己运行模块......
最好的方法是尽快直接进行系统测试,因为单元测试很难维护 - 所以足够的单元测试可以让你进行系统测试往返而不再需要(甚至更好的删除) db单元尽快测试).