Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

What are the ideas for a new standard test SRFI? #3

Open
amirouche opened this issue Aug 4, 2020 · 15 comments
Open

What are the ideas for a new standard test SRFI? #3

amirouche opened this issue Aug 4, 2020 · 15 comments

Comments

@amirouche
Copy link

I read here and there many people have ideas about a new test SRFI.

What are your ideas?

ref: https://srfi.schemers.org/srfi-64/
ref: https://srfi.schemers.org/srfi-78/

@amirouche
Copy link
Author

Here are some thought by mdhughes at https://mdhughes.tech/2020/02/27/scheme-test-unit/

@shirok
Copy link
Collaborator

shirok commented Aug 4, 2020

There are two situations:

  • Per-project test---test frameworks each project can choose to adopt and write tests in. Such frameworks can have as many fancy things as it like.
  • Conformance test ---such as each individual srfi tests. Those tests are expected to be taken into implementations, so that each implementation can run it as a part of the implementation's test suite. Those test interface are expected to be easy to integrate into the implementation's own choice of tests.

My concern is mainly the latter. Gauche supports srfi-64 and srfi-78 (and (chibi test)) in a way that, when used with (gauche test), each test of those srfis become a thin wrapper to the gauche's own test so that the reporting, success/failure count, etc works seamlessly.

We can have sophisticated test framework for the former, but I'd like it to be noted not to be used for the latter kind of tests.

@lassik
Copy link
Member

lassik commented Aug 4, 2020

Thanks for the links.

The most important thing would be to separate the test runner from the test definition framework, so that tests defined using any framework can be run using any runner.

Test runners can be quite complex, and people don't agree on which one is best. Definition frameworks are much simpler, and can be easily ported to new Schemes.

The currently dominant frameworks are SRFI 64 (A Scheme API for test suites, originally from Kawa) and Chicken's test egg which was also adapted by Chibi. Chicken test has an almost identical API to SRFI 64. So lots of Scheme tests are using almost the same syntax already.

I'd like to publish a SRFI that contains:

  • Only the test definition part from SRFI 64, not the test runner.
  • Adds the extra stuff from Chicken/Chibi test (there is not much extra, only a couple of things).
  • Adds a few more minor convenience procedures for testing exceptions.

This definition framework could be supported by any existing test runner.

@lassik
Copy link
Member

lassik commented Aug 4, 2020

For SRFI testing, it would be nice to get the files in this srfi-test repo into a form that many Scheme implementations can import directly (i.e. just copy the .scm file into their repo with no changes). That would make it easy to keep everyone up to date with the latest tests.

I think being able to copy the files with no changes important. Then it's so easy that people will actually do it. If small changes are needed here and there, it will become a burden.

@johnwcowan
Copy link

I want to mention something off-topic but which I think will be of interest to readers of this thread. Every Lisper, and probably every programmer who uses a REPL, does informal testing using the REPL. However, such testing does not generate a reusable artifact: you can't use it to find regressions, for example, except by accident.

The idea here is to enhance Scheme REPLs that support REPL commands to help generate such artifacts. A REPL command is something you can input that by convention is not just another Scheme expression to evaluate. For example, in Chicken the REPL commands take the form ,foo, since (unquote foo) is not meaningful Scheme. In Chibi they look like @FOO, which could be a variable to evaluate but generally isn't. Other conventions are used elsewhere; I'll use Chicken's here. A REPL command can take arguments, usually by callingread to collect them.

The idea is that as you noodle around in the REPL, a test script is being created. You start making such a script with a ,testscript command that specifies the pathname of the test script. Then you go along doing your informal tests like this:

> (+ 1 2)
3
> ,ok

This causes a test case to be written to the file which tests that (+ 1 2) => 3. In SRFI-64 that would be (test-equal 3 (+ 1 2)). The ,ok command needs access to the REPL history and to the last value returned. If multiple values are returned, the test case becomes more complicated; if the returned value is #t or #f, we can get clever and use a different test operation.

To this we can add ,error, which tests that the last evaluation throws an exception, and ,endtest, which closes the test script. All other REPL operations including ordinary evaluation have no effect on the test script.

@arthurgleckler
Copy link

arthurgleckler commented Aug 4, 2020 via email

@johnwcowan
Copy link

I want to mention something off-topic but which I think will be of interest to readers of this thread. Every Lisper, and probably every programmer who uses a REPL, does informal testing using the REPL. However, such testing does not generate a reusable artifact: you can't use it to find regressions, for example, except by accident.

The idea here is to enhance Scheme REPLs that support REPL commands to help generate such artifacts. A REPL command is something you can input that by convention is not just another Scheme expression to evaluate. For example, in Chicken the REPL commands take the form ,foo, since (unquote foo) is not meaningful Scheme. In Chibi they look like @FOO, which could be a variable to evaluate but generally isn't. Other conventions are used elsewhere; I'll use Chicken's here. A REPL command can take arguments, usually by callingread to collect them.

The idea is that as you noodle around in the REPL, a test script is being created. You start making such a script with a ,testscript command that specifies the pathname of the test script. Then you go along doing your informal tests like this:

> (+ 1 2)
3
> ,ok

This causes a test case to be written to the file which tests that (+ 1 2) => 3. In SRFI-64 that would be (test-equal 3 (+ 1 2)). The ,ok command needs access to the REPL history and to the last value returned. If multiple values are returned, the test case becomes more complicated; if the returned value is #t or #f, we can get clever and use a different test operation.

To this we can add ,error, which tests that the last evaluation throws an exception, and endtest, which closes the test script. All other REPL operations including ordinary evaluation have no effect on the test script.

@johnwcowan
Copy link

Test runners can be quite complex, and people don't agree on which one is best. Definition frameworks are much simpler, and can be easily ported to new Schemes.

+1

  • Only the test definition part from SRFI 64, not the test runner.
  • Adds the extra stuff from Chicken/Chibi test (there is not much extra, only a couple of things).
  • Adds a few more minor convenience procedures for testing exceptions.

IMO some further re-engineering is needed. Most of the test-* functions of SRFI 64 exist in order to implicitly supply the equivalence predicate. But SRFI 64 predated parameters and comparators.

I think the Chicken and Chibi test system's use of a parameter current-test-comparator is the Right Thing. The equality predicate of this comparator is used to decide if the expected and actual values are the same. The default comparator's equality predicate is exposed as test-equal?, whose behavior is the same as equal? unless both arguments are inexact numbers, in which case it uses the value of the current-test-epsilon parameter to do a relative error test.

That said, all we really need is test, but test-assert and test-not (in Chibi but not Chicken, for some reason) are convenient. Beyond that, test-error (with an error predicate) is necessary, and you can make a case for test-syntax-error (checks a string to see if it can be evaluated).
Finally, a inimal test-grouping facility: test-group with a mandatory name.

And that's all.

@amirouche
Copy link
Author

I like @arthurgleckler test framework 😃

The problem with SRFI-64 is that it does not allow to run a single test or group of tests separately. That may not be necessary for the small-ish test suite of SRFI, but in a real world scenario where tests take more than a few seconds or minutes to run it becomes necessary to run one test at a time. Another thing that painful about SRFI-64, since the tests are not first-class, it is not possible to run the test in a REPL.

I think we should have something along the lines of @arthurgleckler tests framework.

@amirouche
Copy link
Author

It seems to me having two or more ways to define tests is not a good thing.

@sjamaan
Copy link
Collaborator

sjamaan commented Aug 5, 2020

The CHICKEN (and probably Chibi) test library has a way to filter tests using an environment variable. Howver, as far as I know this just filters the output and still runs all the other tests. I don't know if there's an easy way to support this in a way that it will actually run only the selected tests?

@sjamaan
Copy link
Collaborator

sjamaan commented Aug 5, 2020

Making tests first-class would probably solve the filtering problem too

@lassik
Copy link
Member

lassik commented Aug 5, 2020

Making tests first-class would probably solve the filtering problem too

OK, let's do it. A SRFI for reflection on the available test suites and test cases, and for making new ones. Kind of like a WSGI-style meeting point that sits between test definition frameworks and test runners. All frameworks and runners could be implemented against this interface.

@lassik
Copy link
Member

lassik commented Aug 5, 2020

We should keep all the strictly runner-related concepts out of it though :) That's the stuff where complexity comes form.

@ashinn
Copy link

ashinn commented Aug 27, 2020

The CHICKEN (and probably Chibi) test library has a way to filter tests using an environment variable. Howver, as far as I know this just filters the output and still runs all the other tests. I don't know if there's an easy way to support this in a way that it will actually run only the selected tests?

This doesn't filter output - it only runs the selected tests. It can also be controlled from Scheme via parameters, the init values from env vars are for convenience.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants