首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在Erlang的EUnit中,断言一个函数是用匿名函数调用的

在Erlang的EUnit中,断言一个函数是用匿名函数调用的
EN

Stack Overflow用户
提问于 2022-04-29 20:37:49
回答 2查看 124关注 0票数 1

我有一些代码如下所示:

代码语言:javascript
复制
-module(ca_data).
-export([delete_ca_data/1]).

% ...

delete_ca_data(N) when N < 1 -> ?NEGATIVE_ID_ERROR;
delete_ca_data(N) -> util_db_generic:delete_object(ca_data, N, fun(_) -> ok end).

% ...

我有一些测试代码,如下所示:

代码语言:javascript
复制
wrap_meck(MockMod, MockArgs, F) ->
    meck:new(MockMod, MockArgs),
    try
        F()
    catch Ex ->
        throw(Ex)
    after
        meck:unload(MockMod)
    end.

delete_ca_data_test() ->
    F = fun() ->
        meck:expect(util_db_generic, delete_object, fun (_, _, _) -> ok end),

        ?assertEqual(?NEGATIVE_ID_ERROR, ca_data:delete_ca_data(-1)),

        ?assertEqual([], meck:history(util_db_generic)),

        meck:expect(util_db_generic, delete_object, fun(_, _, _) -> ok end),
        ?assertEqual(ok, ca_data:delete_ca_data(1)),

        ?assertEqual(
            [{self(), {util_db_generic, delete_object, [ca_data, 1, fun(_) -> ok end]}, ok}], % Uh-oh
            meck:history(util_db_generic)
        )
    end,
    wrap_meck(util_db_generic, [], F).

不幸的是,util_db_generic:delete_object函数是通过在测试模块中创建的函数调用的。

这提供了一些问题,当试图断言函数调用的历史记录时(例如,在标记为“Uh-oh”的行上)。因为这个函数是在原地创建的(而且内存指针实际上是随机的),所以断言这个函数应该是什么样子是很困难的。此代码不会导致任何编译错误。但是,断言永远不会返回为有效的,因为有两个不同的函数相互声明(一个在ca_data模块中创建,一个在测试用例中创建)。我尝试使用?assertMatch并将fun(_) -> ok end的out更改为_,但我在assert行上得到了这个编译错误:

代码语言:javascript
复制
illegal pattern

如何才能与这些结果相匹配?

EN

回答 2

Stack Overflow用户

发布于 2022-04-30 10:57:52

您想要的断言可能如下所示:

代码语言:javascript
复制
?assertMatch(
    [{Self, {util_db_generic, delete_object, [ca_data, 1, Fun]}, ok}] when Self == self() andalso is_function(Fun, 1), % Yay?
    meck:history(util_db_generic)
)

这与?assertMatch文档相匹配,因为您将在这样的case语句中编写相同的内容:

代码语言:javascript
复制
case meck:history(util_db_generic) of
    [{Self, {util_db_generic, delete_object, [ca_data, 1, Fun]}, ok}] when Self == self() andalso is_function(Fun, 1) ->
        true;
    _ ->
        false
end

(注意,case语句在警卫之间使用,时可能会更短,但在宏中不起作用,所以这里我们必须使用andalso )。

您必须首先将pid与Self匹配,然后在一个保护程序中检查它的原因是匹配表达式中不允许函数调用:

代码语言:javascript
复制
1> [self()] = [self()].
* 1:2: illegal pattern

因此,您必须先绑定它,然后检查保护中的值。当然,如果您上面所写的,在表达式外绑定Self也是有效的。这只是一个品味和/或可读性的问题(事实上,我认为绑定Self首先更清楚)。

票数 3
EN

Stack Overflow用户

发布于 2022-04-29 20:37:49

虽然Erlang文档通常很好,但这一点让用户失望。The assertMatch documentation states

代码语言:javascript
复制
Evaluates Expr and matches the result against GuardedPattern, if testing is enabled. ... GuardedPattern can be anything that you can write on the left hand side of the -> symbol in a case-clause, except that it cannot contain comma-separated guard tests.

And the documentation for self() states

代码语言:javascript
复制
Allowed in guard tests.

但是,self()函数不能用于assertMatch宏。我不清楚为什么,但实验已经证明了这一点。

编辑1:

情节更复杂了!当我编辑测试代码时,如下所示:

代码语言:javascript
复制
delete_ca_data_test() ->
    F = fun() ->
        meck:expect(util_db_generic, delete_object, fun (_, _, _) -> ok end),

        ?assertEqual(?NEGATIVE_ID_ERROR, ca_data:delete_ca_data(-1)),

        ?assertEqual([], meck:history(util_db_generic)),

        meck:expect(util_db_generic, delete_object, fun(_, _, _) -> ok end),
        ?assertEqual(ok, ca_data:delete_ca_data(1)),

        Self = self(),

        ?assertEqual(
            [{Self, {util_db_generic, delete_object, [ca_data, 1, _]}, ok}], % Uh-oh
            meck:history(util_db_generic)
        )
    end,
    wrap_meck(util_db_generic, [], F).

代码编译并正确运行!对我来说,这是一个令人惊讶的结果!函数(应该可以在警卫中使用)是不允许的,但是函数的返回是!有意思的!

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72063449

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档