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

时间:2015-02-27 20:17:40

标签: unit-testing prolog swi-prolog plunit

作为这个问题的一个例子,我有一个非常简单的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)是事实,进行测试,然后“未声明”他们。但是,此测试也失败了。使用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是正确的谓词定义。虽然感觉类似于我的第三或第四次测试的东西应该能够实现我想做的事情吗?

2 个答案:

答案 0 :(得分: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.

当然,很长一段时间知道在运行时修改程序它是一项危险的活动......无论如何,设置/清理是目标,所以也许你想要< / p>

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 :(得分: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标准一致性测试套件,它为您提供了更多示例。