# Module exports for testing, is this possible?

**URL:** <https://swi-prolog.discourse.group/t/module-exports-for-testing-is-this-possible/2128>\
**Category:** Help!\
**Created:** [April 9, 2020, 11:13am UTC](https://swi-prolog.discourse.group/t/module-exports-for-testing-is-this-possible/2128 "2020-04-09T11:13:22Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![emacstheviking](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/emacstheviking/32/228_2.png) [@emacstheviking](https://swi-prolog.discourse.group/u/emacstheviking)\
**Post date:** [April 9, 2020, 11:13am UTC](https://swi-prolog.discourse.group/t/module-exports-for-testing-is-this-possible/2128/1 "2020-04-09T11:13:22Z")

</div>

I just refactored some tests out into a separate .plt file and it took me a while to get it all stable again but I realised that when the tests were in the same file it was cleaner because now I have had to export the predicates that I want to test.

Is there a way to say “export these for unit testing only” and then list them, maybe something like:

I know I can use Module:Predicate to directly call from the test, which solved my problem, but it means I have to do this all the time.

Have I missed a trick?

TIA  
Sean

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [April 9, 2020, 11:28am UTC](https://swi-prolog.discourse.group/t/module-exports-for-testing-is-this-possible/2128/2 "2020-04-09T11:28:59Z")

</div>

Typically, cross-module calls are considered ok for testing and debugging (and for some real code). You can dynamically import any predicate from a module. Don’t tell @pmoura 🙂

```
:- export(m:p/1).
:- import(m:p/1).
```

---

<div class="post-metadata">

**Author:** ![emacstheviking](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/emacstheviking/32/228_2.png) [@emacstheviking](https://swi-prolog.discourse.group/u/emacstheviking)\
**Post date:** [April 9, 2020, 11:30am UTC](https://swi-prolog.discourse.group/t/module-exports-for-testing-is-this-possible/2128/3 "2020-04-09T11:30:57Z")

</div>

Superb!!!

Thanks Jan. In the last week since the lockdown, I have absolutely dived into SWI and it just keeps on giving.

🙂

---

<div class="post-metadata">

**Author:** ![emacstheviking](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/emacstheviking/32/228_2.png) [@emacstheviking](https://swi-prolog.discourse.group/u/emacstheviking)\
**Post date:** [April 9, 2020, 11:34am UTC](https://swi-prolog.discourse.group/t/module-exports-for-testing-is-this-possible/2128/4 "2020-04-09T11:34:04Z")

</div>

I read the documentation and as usual it’s all there… problem is though I didn’t read that far in the first place. I started breaking my project into modules this week and when I got the “hang” of it, I ploughed on and looking at the title “An alternative import/export interface” I guess the word alternative was “don’t need this”!

I hereby do solemnly swear never to use `import/1` other than for tests!

---

<div class="post-metadata">

**Author:** ![pmoura](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/pmoura/32/11_2.png) [@pmoura](https://swi-prolog.discourse.group/u/pmoura)\
**Post date:** [April 9, 2020, 11:35am UTC](https://swi-prolog.discourse.group/t/module-exports-for-testing-is-this-possible/2128/5 "2020-04-09T11:35:12Z")

</div>

> [@jan](#):
>
> Don’t tell @pmoura 🙂

😄😄😄 I agree with you. With tests in a separate module (as with `plunit`) or a separate object (as with `lgtunit`), we often need to test more than just the exported or public predicates. Ideally, just be calling the exported or public predicates, all predicates in the _unit_ would be triggered. But in practice that may not provide the sought code coverage. So, (ab)using `:/2` to call auxiliary predicates (in the case of Logtalk, there’s a `<</2` context-switching debugging control construct that can be enabled and used also for testing) is fine in this particular case.

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [April 9, 2020, 11:35am UTC](https://swi-prolog.discourse.group/t/module-exports-for-testing-is-this-possible/2128/6 "2020-04-09T11:35:48Z")

</div>

> [@emacstheviking](#):
>
> “An alternative import/export interface”

I don’t like this interface much, but it can be useful for dynamically created modules and compatibility with some other Prolog systems. And for dirty hacking …

---

<div class="post-metadata">

**Author:** ![emacstheviking](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/emacstheviking/32/228_2.png) [@emacstheviking](https://swi-prolog.discourse.group/u/emacstheviking)\
**Post date:** [April 9, 2020, 11:39am UTC](https://swi-prolog.discourse.group/t/module-exports-for-testing-is-this-possible/2128/7 "2020-04-09T11:39:07Z")

</div>

It’s a frequent issue for many languages I guess. For me though, I like to TDD my way through as I am still a relative plank / n00b with Prolog!

One of the frustrations is that when a predicate fails, it all fails and you are left scratching your head. I learned today I can put a call to `gtrace` and have the debugger pop open when truly stuck…I always view using the debugger as a sign of personal failure 😃

This week I also used properly “print\_message” thanks to Anns great tutorial on the matter. It’s all coming together… I just don’t know what it will be when it’s finished…

---

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [April 9, 2020, 11:48am UTC](https://swi-prolog.discourse.group/t/module-exports-for-testing-is-this-possible/2128/8 "2020-04-09T11:48:36Z")

</div>

> [@emacstheviking](#):
>
> It’s a frequent issue for many languages I guess.

You are correct. In some languages it perplexes many new programmers because they think the modifiers like _private_ mean the code is inaccessible on the physical machine when in reality it is just a concept used by the compiler. So it is not a guess, it is a problem that many but not all programming languages have.

**EDIT**

There are many articles/blogs/post like this on the internet: [Testing Private Methods with JUnit and SuiteRunner](https://www.artima.com/suiterunner/private.html)

Just search for _unit test private method_.

---

<div class="post-metadata">

**Author:** ![emacstheviking](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/emacstheviking/32/228_2.png) [@emacstheviking](https://swi-prolog.discourse.group/u/emacstheviking)\
**Post date:** [April 9, 2020, 11:58am UTC](https://swi-prolog.discourse.group/t/module-exports-for-testing-is-this-possible/2128/9 "2020-04-09T11:58:21Z")

</div>

```prolog
Warning: /home/sean/Documents/code/prolog/the-f-word-project/tokeniser.plt:4:
	import/1: tokeniser:new_token/4 is not exported (still imported into plunit)

```

Is there a way to turn this off or am I stuck with warnings because I dared to use a dirty hack for testing? I might as well just make it all exported from the module for an easy life…

---

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [April 9, 2020, 12:11pm UTC](https://swi-prolog.discourse.group/t/module-exports-for-testing-is-this-possible/2128/10 "2020-04-09T12:11:31Z")

</div>

> [@emacstheviking](#):
>
> I might as well just make it all exported from the module for an easy life

Don’t do that as many programmers know that predicates that are not exported should not be called outside of the module without good reason, e.g. testing. Another reason that the predicates may not be exposed is because they implement variations depending on conditions like which OS they are on or which version of Prolog they are emulating. Calling the non-exported predicates can have disastrous results when in other context, e.g. run on another OS, etc. Do yourself a favor and be very judicial about which predicates get exported and why and in the long run your code will be better.

However in some cases it is later realized that a predicate should be exported because it has been enhanced or the programmer felt it should not be exported but others point out reasons that it should be exported.

A case in point where a predicate is not exported and I used it only to find out that I was using the module incorrectly. The predicate that was not exported was [has\_type/2](https://github.com/SWI-Prolog/swipl-devel/blob/86a11697f52b6f06c43ef662facd2d6f232c5fd1/library/error.pl#L333) and the predicate to use was either [must\_be/2](https://github.com/SWI-Prolog/swipl-devel/blob/86a11697f52b6f06c43ef662facd2d6f232c5fd1/library/error.pl#L36) or [is\_of\_type/2](https://github.com/SWI-Prolog/swipl-devel/blob/86a11697f52b6f06c43ef662facd2d6f232c5fd1/library/error.pl#L36)

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [April 9, 2020, 12:20pm UTC](https://swi-prolog.discourse.group/t/module-exports-for-testing-is-this-possible/2128/11 "2020-04-09T12:20:12Z")

</div>

> [@emacstheviking](#):
>
> Is there a way to turn this off

That is what the `:- export(tokeniser:new_token/4).` that you should add before the import does. You first tell another module to export one of its private predicates (that is the dirty part, but ok for this purpose), _then_ you import (you can now also use `:- use_module(...)`).

---

<div class="post-metadata">

**Author:** ![pmoura](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/pmoura/32/11_2.png) [@pmoura](https://swi-prolog.discourse.group/u/pmoura)\
**Post date:** [April 9, 2020, 12:25pm UTC](https://swi-prolog.discourse.group/t/module-exports-for-testing-is-this-possible/2128/12 "2020-04-09T12:25:51Z")

</div>

Dirty hack indeed, even if just for this purpose. Something along the lines of Logtalk’s [`<</2`](https://logtalk.org/manuals/refman/control/context_switch_2.html) or ECLiPSe’s [`@/2`](http://eclipseclp.org/doc/bips/kernel/control/A-2.html) control constructs would be arguably cleaner.

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [April 9, 2020, 12:32pm UTC](https://swi-prolog.discourse.group/t/module-exports-for-testing-is-this-possible/2128/13 "2020-04-09T12:32:55Z")

</div>

Well, good old Quintus `Module:Goal` works fine, but apparently @emacstheviking doesn’t like to type that all over the place. Note that another way is adding a clause like this:

```
 new_token(A,B,C,D) :- tokeniser:new_token(A,B,C,D).

```

In this case this does precisely what you (probably) want: call new\_token/4 in the context of `tokenizer`. The @/2 is also in SWI-Prolog, but not as an operator. It was added for compatibility reasons and I’ve found a few use cases since.

---

<div class="post-metadata">

**Author:** ![emacstheviking](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/emacstheviking/32/228_2.png) [@emacstheviking](https://swi-prolog.discourse.group/u/emacstheviking)\
**Post date:** [April 9, 2020, 1:05pm UTC](https://swi-prolog.discourse.group/t/module-exports-for-testing-is-this-possible/2128/14 "2020-04-09T13:05:48Z")

</div>

Sigh. I didn’t realise that I had to use export first./…I mean I actually saw your reply but I just thought you were showing me export and import…I had no notion they were to be used together like that! 😃 Sometimes I wonder how I manage to dress myself.

---

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [April 9, 2020, 1:07pm UTC](https://swi-prolog.discourse.group/t/module-exports-for-testing-is-this-possible/2128/15 "2020-04-09T13:07:30Z")

</div>

> [@emacstheviking](#):
>
> Sometimes I wonder how I manage to dress myself.

At least you have found the path and are walking on it. 🙂

---

<div class="post-metadata">

**Author:** ![emacstheviking](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/emacstheviking/32/228_2.png) [@emacstheviking](https://swi-prolog.discourse.group/u/emacstheviking)\
**Post date:** [April 9, 2020, 1:13pm UTC](https://swi-prolog.discourse.group/t/module-exports-for-testing-is-this-possible/2128/16 "2020-04-09T13:13:05Z")

</div>

😃 yes sir!

I have to say, having been in software development since the age of 19, after 35 years, I still love learning things, usually the hard way and ever since I discovered Lisp about 20 years ago, Prolog was always “that language” I had yet to confront. I think I was 7 years old when Prolog('72) was released so I can be excused for not being aware of it then!

On and off (more off than on to be honest) over the last years I have now started to realise that most languages are full of stuff nobody uses or needs. After a while you realise that most “software” is either number crunching or string bashing and pretty much that’s all you need.

I am continually blown away by the things I learn about Prolog. I have been lucky enough to obtain real books of Clocksin&Mellish, Learn Prolog Now!, Art of Prolog, Craft of Prolog, and Prolog Programming in Depth and between them I still know I have a lot to learn!

Might as well say a big big thanks to everybody around these here parts for such great answers and patience with me… “logic” programming is something that you could spend a lifetime understanding the nuances, only in the last couple of weeks have I truly grasped (I think!) what choice points, cuts and backtracking really are doing. Loving it!
