首页 文章

仅在SWI-Prolog中的单个单元测试范围内声明真实的事实

提问于
浏览
1

作为这个问题的一个例子,我有一个非常简单的Prolog文件 main.pl ,其中我定义了一些形状的颜色 .

colour(circle, red).
colour(triangle, red).
colour(square, blue).

现在,我定义了一个谓词 same_colour/2 ,如果 S1S2 是相同的颜色,则为真 .

same_colour(S1, S2) :-
    colour(S1, C),
    colour(S2, C).

顶级测试表明此谓词按预期工作 .

?- same_colour(circle, triangle).
true.

?- same_colour(circle, square).
false.

我正在尝试使用SWI-Prologs单元测试框架plunitsame_colour/2 编写单元测试,但我想在每个单独的测试中声明只在该测试范围内的事实 . 我已尝试将 setup 选项用于单个测试,以及 asserta ,两者都不起作用 . 以下所有测试都失败了 .

:- begin_tests(same_colour).

test(same_colour) :-
    colour(shape_a, colour_1),
    colour(shape_b, colour_1),
    same_colour(shape_a, shape_b).

test(same_colour) :-
    asserta(colour(shape_a, colour_1)),
    asserta(colour(shape_b, colour_1)),
    same_colour(shape_a, shape_b).

test(same_colour, [
    setup(colour(shape_a, colour_1)),
    setup(colour(shape_b, colour_1))
]) :-
    same_colour(shape_a, shape_b).

:- end_tests(same_colour).

我也尝试过:

test(same_colour, [
    setup(asserta(colour(shape_a, colour_1))),
    setup(asserta(colour(shape_b, colour_1))),
    cleanup(retract(colour(shape_a, colour_1))),
    cleanup(retract(colour(shape_b, colour_1)))
]) :-
    same_colour(shape_a, shape_b).

也就是说,首先声明 colour(shape_a, colour_1)colour(shape_b, colour_1) 是事实,进行测试,然后'undeclare' . 但是,此测试也失败了 . 使用 trace 似乎 colour(shape_a, colour_1) 永远不会被断言(或者在我的测试运行时至少不是真的 . )

Call: (18) plunit_same_colour:'unit body'('same_colour@line 13', vars) ? creep
Call: (19) same_colour(shape_a, shape_b) ? creep
Call: (20) colour(shape_a, _G738) ? creep
Fail: (20) colour(shape_a, _G738) ? creep
Fail: (19) same_colour(shape_a, shape_b) ? creep
Fail: (18) plunit_same_colour:'unit body'('same_colour@line 13', vars) ? creep

我现在可以理解为什么前两个测试不起作用 . 在第一个我正在测试 colour(shape_a, colour_1) 是否为真,当它没有't been declared before, and in the second I just don'认为在谓词定义中使用 asserta 是正确的 . 虽然感觉类似于我的第三或第四次测试应该能够实现我想做的事情?

2 回答

  • 1

    测试你的测试:)

    :- module(colour_test, [same_colour/2]).
    :- use_module(library(plunit)).
    
    colour(circle, red).
    colour(triangle, red).
    colour(square, blue).
    
    same_colour(S1, S2) :-
        colour(S1, C),
        colour(S2, C).
    
    :- begin_tests(same_colour).
    
    test(same_colour) :-
        colour(shape_a, colour_1),
        colour(shape_b, colour_1),
        same_colour(shape_a, shape_b).
    
    test(same_colour) :-
        asserta(colour(shape_a, colour_1)),
        asserta(colour(shape_b, colour_1)),
        same_colour(shape_a, shape_b).
    
    test(same_colour, [
        setup(colour(shape_a, colour_1)),
        setup(colour(shape_b, colour_1))
    ]) :-
        same_colour(shape_a, shape_b).
    
    :- end_tests(same_colour).
    

    产量

    1 ?- run_tests(same_colour).
    % PL-Unit: same_colour 
    ERROR: /home/carlo/prolog/so/colour_test.pl:14:
        test same_colour: failed
    
    ERROR: /home/carlo/prolog/so/colour_test.pl:19:
        test same_colour: received error: asserta/1: No permission to modify static procedure `colour_test:colour/2'
    Defined at /home/carlo/prolog/so/colour_test.pl:4
    ERROR: goal unexpectedly failed: colour(shape_a,colour_1)
     done
    % 2 tests failed
    % 0 tests passed
    false.
    

    也就是说,如果你想在运行时修改数据库,请让Prolog知道,添加:

    :- dynamic colour/2.
    

    现在它变得更好了:

    2 ?- run_tests(same_colour).
    % PL-Unit: same_colour 
    ERROR: /home/carlo/prolog/so/colour_test.pl:16:
        test same_colour: failed
    
    .. done
    % 1 test failed
    % 2 tests passed
    false.
    

    但数据库是“脏”的:

    3 ?- listing(colour).
    :- dynamic colour_test:colour/2.
    
    colour_test:colour(shape_b, colour_1).
    colour_test:colour(shape_a, colour_1).
    colour_test:colour(circle, red).
    colour_test:colour(triangle, red).
    colour_test:colour(square, blue).
    
    true.
    

    当然,它是一项危险的活动......无论如何,设置/清理是目标,所以也许你想要

    test(same_colour, [
        setup(( assertz(colour(shape_a, colour_1)),
                assertz(colour(shape_b, colour_1))
        )),
        cleanup(retractall(colour(_, colour_1)))
    ]) :-
        same_colour(shape_a, shape_b).
    
  • 1

    您可以在替代Logtalk的单元测试框架中使用简单的解决方案:

    https://github.com/LogtalkDotOrg/logtalk3/blob/master/tools/lgtunit/NOTES.md

    SWi-Prolog是十二种支持的Prolog系统之一 . 无需使用 dynamic/1 指令或清理目标 .

    例如,假设您要使用三组事实来测试代码 . 此外,假设要测试的代码在 same_color.pl Prolog文件中定义 . 只需为每组事实定义一个单元测试对象:

    :- object(colors1, extends(lgtunit)).
    
        :- include('same_color.pl').
    
        colour(circle, red).
        colour(triangle, red).
        colour(square, blue).
    
        test(colors1) :-
            ...
    
    :- end_object.
    

    定义对象,例如 colors2colors3 用于其他事实 . 然后:

    | ?- logtalk_load(lgtunit(loader)).
    ...
    | ?- logtalk_load([colors1, colors2, colors3], [hook(lgtunit)]).
    ...
    | ?- colors1::run, colors2::run, colors3::run.
    

    或者只需通过定义 tester.lgt 帮助文件并运行 logtalk_tester 自动化shell脚本来自动化单元测试 . 大量示例,包括Logtalk发行版中的示例 tester-sample.lgt 文件 . 如果您发现使用Logtalk单元测试工具测试Prolog代码很奇怪,请知道Logtalk发行版包含完整的Prolog标准一致性测试套件,它为您提供了更多示例 .

相关问题