2

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

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

现在在下面我定义一个 predicate 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 单元测试框架plunit编写单元测试same_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)是事实,进行测试,然后“取消声明”它们。但是,此测试也失败了。使用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)为真,当它之前没有被声明时,第二个我只是不认为asserta在谓词定义中使用它是正确的。虽然感觉类似于我的第三次或第四次测试应该能够实现我想要做的事情?

4

2 回答 2

2

测试你的测试:)

:- 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).
于 2015-02-28T07:20:19.863 回答
1

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

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

SWi-Prolog 是十二个受支持的 Prolog 系统之一。无需使用dynamic/1指令或清理目标进行黑客攻击。

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

:- 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 脚本来自动化单元测试。大量示例,包括tester-sample.lgtLogtalk 发行版中的示例文件。如果您觉得使用 Logtalk 单元测试工具来测试 Prolog 代码很奇怪,请知道 Logtalk 发行版包含完整的 Prolog 标准一致性测试套件,它为您提供了更多示例。

于 2015-02-28T12:47:06.800 回答