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

Unit testing 在SWI Prolog中声明仅在单个单元测试范围内为真的事实,unit-testing,prolog,swi-prolog,plunit,Unit Testing,Prolog,Swi Prolog,Plunit,作为这个问题的一个例子,我有一个非常简单的Prolog文件main.pl,其中定义了一些形状的颜色 colour(circle, red). colour(triangle, red). colour(square, blue). 下面我定义了一个谓词same_color/2,如果S1和S2都是相同的颜色,则该谓词为真 same_colour(S1, S2) :- colour(S1, C), colour(S2, C). 顶层测试表明该谓词按预期工作 ?- same_col

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

colour(circle, red).
colour(triangle, red).
colour(square, blue).
下面我定义了一个谓词
same_color/2
,如果
S1
S2
都是相同的颜色,则该谓词为真

same_colour(S1, S2) :-
    colour(S1, C),
    colour(S2, C).
顶层测试表明该谓词按预期工作

?- same_colour(circle, triangle).
true.

?- same_colour(circle, square).
false.
我试图使用SWI Prologs单元测试框架为
相同颜色/2
编写单元测试,但我想声明每个测试中的事实,这些事实仅在该测试范围内是正确的。我已经尝试将
设置
选项用于单个测试,以及
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).
也就是说,首先声明
颜色(形状a,颜色1)
颜色(形状b,颜色1)
是事实,进行测试,然后“取消声明”。然而,这个测试也失败了。使用
trace
似乎从未断言过
color(shape\u a,color\u 1)
(或者至少在测试运行时不是真的)

我现在可以理解为什么前两个测试不起作用了。在第一个例子中,我正在测试
color(shape\u a,color\u 1)
是否为真,而在第二个例子中,我认为在谓词定义中使用
asserta
是不正确的。虽然感觉类似于我的第三次或第四次测试,但应该能够实现我的目标?

测试您的测试:)

屈服

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.
也就是说,如果要在运行时修改DB,请告知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.
但DB是“脏的”:

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).

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

SWi Prolog是12个受支持的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.
为其他事实集定义对象,例如
colors2
colors3
。然后:

| ?- logtalk_load(lgtunit(loader)).
...
| ?- logtalk_load([colors1, colors2, colors3], [hook(lgtunit)]).
...
| ?- colors1::run, colors2::run, colors3::run.
或者简单地通过定义
tester.lgt
帮助文件并运行
logtalk\u tester
automation shell脚本来自动化单元测试。大量示例,包括Logtalk发行版中的sample
tester sample.lgt
文件。如果您觉得使用Logtalk单元测试工具测试Prolog代码有点奇怪,请知道Logtalk发行版包含一个完整的Prolog标准一致性测试套件,它为您提供了进一步的示例

:- object(colors1, extends(lgtunit)).

    :- include('same_color.pl').

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

    test(colors1) :-
        ...

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