[ALL] A proposed extension to the test-runner spec #1418
Replies: 13 comments 1 reply
-
FWIW, this is exactly what JavaScript had, but @iHiD had reasons why that wasn't "enough"; I don't recall those reasons, but it was probably important. Jeremy, do you still recall those convo's we had? |
Beta Was this translation helpful? Give feedback.
-
Thanks for the writeup, @TheLostLambda! :) I'm fine with moving the output into the
Yes :)
No (see below)
Yes. Look at the research UI. The different parts of this (cmd, expected, actual) are in demarcated areas. I want this level of granular control within the UI so that our product/UX team can work out how it's best displayed for student clarity, rather than track teams making their own per-track decisions. |
Beta Was this translation helpful? Give feedback.
-
Oh yeah, I definitely want a standard (and not track-specific decisions) but you didn't want the As for JS/TS, we can generate all the required fields from a custom test runner/helper. |
Beta Was this translation helpful? Give feedback.
-
@iHiD I think that adding Also, I can develop a script that takes the Do you reckon that would be a good compromise? We would get all of the additional flexibility of this proposal with only a one-line change for those who wish to continue with the |
Beta Was this translation helpful? Give feedback.
-
I didn't want the output to be in the test-runner. In this proposal it's still in the tests, just extracted (e.g. if it's in the comments, or via AST). The crucial thing is that we can change the output without redeploying the test-runner.
This would make me happy, yes. Let's get a couple of POCs (@ErikSchierboom maybe does C# and F# which are quite different internally, and you do CL) and let's see if they're as easy as we hope :) |
Beta Was this translation helpful? Give feedback.
-
Sounds good! I'll give it a go sometime this week I hope! |
Beta Was this translation helpful? Give feedback.
-
Sidebar question that may have been covered in other discussions.
Is it not a benefit that a student would learn what output from a testing framework idiomatic to that language would look like , and learn to parse it? If is is non-trivial, should track's explain it (maybe as part of the first concept)? |
Beta Was this translation helpful? Give feedback.
-
I'd say a track should maybe explain this, yes. But only once the person is comfortable in a language. The test-suite is going to contain loads of extra ideas/concepts that a student won't be familiar with at the start, so we don't want to have to expose them to that until they're comfortable. I've personally found having to decipher test-suites a real blocker to learning certain languages via Exercism. |
Beta Was this translation helpful? Give feedback.
-
Let's not forget that |
Beta Was this translation helpful? Give feedback.
-
Definitely ☝️ . I can even remember a Ruby exercise in which I couldn't even properly read the tests, even though I did have some experience in Ruby. |
Beta Was this translation helpful? Give feedback.
-
TL;DR I've written a PoC for the C# test runner that outputs the command, expected value and human-friendly test name automatically. IntroductionI've worked on a PoC last week to see if I could modify the C# test runner to output all required information directly in the Implementation
I've not made this exhaustive, but the PoC code shows how easy it is to do this.
However, in some cases there will be some setup code involved too, so the PoC also takes them into account: public void TestInstance()
{
var car = new Car();
car.Speedup();
car.Brake();
Assert.Equal(10, car.Speed());
} This code will result in the following command (effectively everything but the assertion and the expected value:
This works due to the test methods using a consistent naming format, and having a library that allows converting strings to a normal, human-readable format. DifficultyWriting the above code wasn't that hard (2,5 hours work or so), but that was mainly due to the fact that the C# test runner had several things that work in its advantage:
Furthermore, I had some experience with C# AST's having already written the C# representer and analyzer. As other tracks will also have to write a representer, that knowledge will be essential if you want to do something similar to the C# PoC. It could also work the other way around, where writing a representer becomes easier having worked with AST's in the test runner. AlternativesNot all languages will have the above options available. I suspect converting an AST back to code is not built-into all compiler frameworks, but there may be libraries available to do this. An alternative to do this is to do some text processing on the source code of the test suite, to extract the source code as text and do text manipulation. This can be tedious to write and error-prone. As an alternative to any text-based processing, one could also look into adding comments to test methods and then using that as the source. As an example, in C# methods can be annotated with structured XML comments that can relatively easily be accessed in code: /// <summary>My test method</summary>
/// <returns>2</returns>
/// <example>
/// var car = new Car();
/// car.Speed();
/// </example>
public void MyTestMethod()
{
var car = new Car();
Assert.Equal(2, car.Speed());
} If there is no structured comment option, one could consider defining one. The text- and comment-based options are less than ideal, as they are either error-prone (text-based) or possibly out of sync with the actual code (command-based). Manual optionsFor the above reasons and the fact that we don't want to force tracks to output this information automatically, we should have some manual option available too (the N.B. the C# test runner PoC is PoC code, which means that it hasn't been cleaned-up/refactored. |
Beta Was this translation helpful? Give feedback.
-
Very cool Erik! 🚀 I feel like this part is critical though, for the tracks that may have the difficulties that Erik has mentioned:
|
Beta Was this translation helpful? Give feedback.
-
@iHiD and I will be working on a comments based (annotations) approach to this, that can be used across almost all tracks. I think that proves that this proposal has merit. I'm behind both. |
Beta Was this translation helpful? Give feedback.
-
The Problem
When using the new, in-browser coding in v3, it's important that the student is given detailed and easy to understand error messages when a given test fails. This means abstracting away as much of the testing framework as possible. While some test runners may be able to return the testing code run via the
results.json
output of the test-runner, this faces a couple of limitations. For example, in the Common Lisp Pokémon battle exercise, a single test looks like this:The test-runner then returns this code to the student when that test fails. The are a number of issues with this:
is
, something which is not part of the language standard or a concept being taught.make-test-pokemon
which is private to the test file.The Current System
The "beta" for parts of v3, research.exercism.io, solves this problem by having an additional JSON file (.meta/config.json) for each exercise with a list of test fields that look like the following:
Pros:
cmd
field) has all of testing-specific cruft stripped away. There are no library functions, no equality testing, no opaque helper functions.expected
field. There is no work the student needs to do to find the proper return value.Cons:
.meta/config.json
file shown above is nearly 100 lines. The repetitive nature is reflected in the fact that a bzip2 compressed.meta/config.json
goes from 4.8K to just 801 bytes..meta/config.json
file. This has already resulted in production bugs (and, in my opinion, not by the fault of the maintainers)..meta/config.json
is brittle. Thetest
field of.meta/config.json
must match thename
field of the test-runnerresults.json
file. If the name of a test is changed in the test suite, then.meta/config.json
breaks.results.json
and.meta/config.json
files are also somewhat redundant in themessage
andcmd
fields. Both fields are meant to relay to the user information about a test-failure..meta/config.json
– it becomes twice as much work to write a test file. Additionally,.meta/config.json
doesn't have any validity checking, so a forgotten parenthesis or semi-colon will often go unnoticed.Some Solutions
Automatically generating the
.meta/config.json
fileThis certainly isn't a bad idea, but isn't a magical solution either. How do you keep the
.meta/config.json
up to date with the test suite? Do you add it as an automatic CI option? While that's an option, it puts a lot of faith in the automated generator. On that subject, these automated generators would almost-certainly be track specific so there would likely need to be a different CI check for every track (disclaimer: I'm not a CI expert).My Proposed Solution: Extending the test-runner spec
I think that a lot of the aforementioned problems could be mitigated if the functionality of the
.meta/config.json
file were integrated into the test runner.This would allow each individual track to decide how best to generate human-friendly errors
Some options are:
Continue using
.meta/config.json
There are some tracks where it's somewhat impractical to do any automated error generation. All test runners already have the ability to write JSON files, so it's reasonable to assume that a number of them can also read JSON. The test runner simply reads some sort of
config.json
and writes that directly (or with some formatting) toresults.json
.Generation via Comments
This idea is from @iHiD! It was suggested that tests could be annotated with a comment containing some information about the correct message to show. Something like:
While this still involves some duplication, all of the test code is in the same place. If you make a change to the test, it's easy enough to edit the line right above it. In some languages, you could easily uncomment and test this code is valid as well.
Fully Automated Generation
This would be different for every track and likely involve some AST parsing (unless your language's syntax is its AST tree, Lisp FTW 😉). Implementing this would mean no more duplication of testing information.
A Hybrid Approach + Literally Anything Else
Maybe you are able to automatically generate messages in 90% of cases but need to fall-back to a comment-annotation or
config.json
, that's not a problem! If you want to do things differently, you only need to work with the people in your track and don't need to write massive Github issues like this.The real advantage of shifting this responsibility to the test-runner is flexibility
Some Questions I Still Have
Should we change the
tests
field ofresults.json
? It currently looks like this:Should we add the
cmd
andexpected
fields from the.meta/config.json
? Something like this?Or is that just more silly redundancy and this is best?
I'd love to know what people think! Sorry for the marathon GitHub issue!
Beta Was this translation helpful? Give feedback.
All reactions