Closed yumaikas closed 3 years ago
@pyrmont Is this something that you're interested in, or should I close out this PR?
@yumaikas I'm interested. I think you've identified a real problem but I also want to properly consider changes to Testament's API.
Ok, cool. I could turn this into an issue, then. I am using this in some of my current tests, so I'll be hanging on to my branch for the time being.
It's up to you but I have no problem with it being left as an outstanding PR if that's easiest.
@pyrmont I'm ok leaving it as an outstanding PR.
Which then means we can go into consideration:
What do you think is missing from this PR? Should the name be different? Should it take some of the arguments that run-tests!
does? I gather that something about it doesn't quite sit well in your mind, I'd like to have an idea as to what.
Here are the questions I'm thinking about at the moment:
I like what defsuite!
looks like but it feels incorrect to me that a def
-something would cause something like run-tests!
to run. Wouldn't it make more sense to call it something like run-suite!
? Except what is the 'suite' that it would run? None has been defined at the point it's called. Maybe it should be run!
? Or test!
? Or exercise!
?
In a similar vein, it's called defsuite
but it doesn't actually creating a binding. Should it create some kind of binding? But what would be the purpose of such binding if it did create one? If it did create a binding, should there also be a run-suite!
function?
run-tests!
calls os/exit
as a way to stop jpm
if there are failing tests (because otherwise jpm test
will print out All tests passed.
even if there are no passing tests). You can pass run-tests!
the :exit-on-fail
parameter to stop it from exiting but if you pass this parameter, run-tests!
doesn't actually tell you whether the tests were passed or not. To be clear, this is an existing problem with Testament not your PR but perhaps it makes sense to fix that and return some value to indicate what tests passed/failed (perhaps including a data structure?) and have defsuite!
proxy the parameters to, and return value from, run-tests!
.
So, I think that do-tests
might be a more accurate name. The !
on the end of the name was supposed to imply that something else was going on.
I think one thing that's going on is that right now, janet has a default assumption that tests will run automatically, where Testament assumes that the user will explicitly run tests.
I think, perhaps, that what might make more sense in the long run is to go from deftest to a test! macro that checks to see if it is part of a defsuite. If it isn't then it runs normally, if it is, then defsuite registers it to it's suite. Once a suite is done, it might call run-tests.... That's one thing that's kinda strange about testament's assertations: They are assertiony outside of a deftest
Thinking on it a bit, the following examples come to mind:
Tests that just run, without a suite surrounding them
(def mytime (os/mktime { :year 2008 :month 0 :month-day 21 }))
(def weekday (dt/weekday-str mytime))
(test! weekday-str
(assert-equal "tuesday" weekday))
Tests that are part of a suite"
(suite! [date-and-time-tests :exit-on-fail true]
(def mytime (os/mktime { :year 2008 :month 0 :month-day 21 }))
(def weekday (dt/weekday-str mytime))
(test! weekday-str
(assert-equal "tuesday" weekday)))
Then, defsuite might delay tests until run-tests is called.
I liked your do-tests
name so I went with that. My idea for the API was that it should be possible to pass a bracketed tuple (e.g. [:silent true]
) as the first argument to do-tests
and have it use that as the arguments for run-tests!
. That's what this does at the moment. What do you think?
Looks good to me! :shipit:
I spent some more time thinking about do-tests
and I decided in the end that I'd prefer a different name (I've gone with exercise!
).
The new exercise!
does three things:
Consistent syntax: The name do-tests
suggested that the macro would operate in the same way as do
but this wasn't actually the case. Since we need a way to pass arguments to run-tests!
, the previous version allowed a user to pass arguments using a bracketed tuple as the first argument. This syntax suggested that the macro would operate in the same way as let
but that wasn't actually the case either. The new exercise!
uses consistent syntax. The first argument must be a tuple and the remainder of the forms are evaluated in a do-form. That tuple can be empty if no arguments are to be passed.
Use ! as a warning: After further reflection, I think the macro should end in !
. This was not clear in the documentation but one of the reasons why it's run-tests!
(rather than run-tests
) is that the function will call os/exit
by default and this will cause a Janet process to immediately terminate. Since the exercise!
macro has the same side effect, it should be named similarly. (I have updated the docstring for run-tests!
to make this behaviour clearer.)
Cleaning up: Since the impetus for this PR was for a way to perform the testing in 'one hit', as it were, I think the macro should also call reset-tests!
at the end. The macro now does that.
I appreciate your patience. I realise this is taking some time but I want to make sure I'm comfortable with new syntax before deciding how to add it. Do you have any additional thoughts?
What does reset-tests! do? If I exercise!
multiple times in a single file, will that cause problems? (I do that for defsuite!
in some of my current testatment-based suites, I'm curious as to what the change will be there).
So, after adding that to my local defsuite!
, it looks like not having that as part of exercise!
would be a bug, so definitely keep it added.
Once you get this merged, I'll move my suites using defsuite!
over to exercise!
and report back if anything important got missed. It's a simple enough underlying structure, however, I don't anticipate much difficulty, now that the names are in a better place.
Testament uses a number of top-level variables to track the performance of the test suite:
Assuming you're using the code you originally submitted in the PR, I would have expected multiple calls to defsuite!
to produce incorrect test output as each call to defsuite!
will cause things like num-tests-run
to keep incrementing.
So, after adding that to my local
defsuite!
, it looks like not having that as part ofexercise!
would be a bug, so definitely keep it added.
I gather that's what you were noticing?
Yes, that is what I was noticing.
How would these reporting vars work if testing was to get multithreaded? I think Janet would do the "right" thing, and each thread would have it's own copy of the globals?
That's my understanding, too, and seems to be how things work based on some quick tests. Fortunately, that's all implementation so if it turns out to be different, I can look at going with a more thread-safe alternative.
defsuite
is a macro that automatically callsrun-tests!
after executing the body passed to it. It is intended to make (run-tests!) harder to forget, as I've forgotten it twice already. I prefer having something I write up front (in the pattern of defer), rather than something I have to remember at the end.