Thanks!
Anton
I'm not quite sure what you're trying to achieve, and I'm not really a Java guru, so I think you might have to experiment a bit. Just a couple of comments:
Thanks for the reply Richard - it's the latter. Yes, I need to experiment. I thought there might be some restrictions in place on these kinds of activities, e.g. reflection is generally turned off in production systems.
Hi Richard,
I've now gone quite a long way with this, but I'm finding myself in a bit of a catch-22.
If Student_answer is not part of the Tester class in the usual way (instead I assign it to a string) I can compile and catch compilation errors myself. But then I can't run unit tests, as the student's code isn't visible in the Tester class. I can create .class files so I could load the student's classes dynamically, but this complicates the unit tests considerably. The student's .class files are created too late for Tester to include code that references the student's answer directly.
If the student's code is included in the class in the standard way then all works in the usual way - if their code contains errors then Tester won't compile, and I can't run my compilation code to catch those errors if Tester doesn't compile.
My idea was to use Precheck to do a free (no marks lost) check, including compilation error check, then Check to run the usual unit tests (with penalties for errors). Is there something in Twig that would allow me to selectively include student_answer perhaps? Or perhaps you can see another way around this problem...
Thanks!
Anton
Hi Anton
Since my Java's a bit rusty, I'm not sure I fully understand the problem. But the way I deal with issues like this in Python, say when scripting C questions, is firstly to get all the input data - student program, test code, etc - as strings. I like to do that first, to avoid cluttering the rest of the template with ugly Twig syntax. Then I write the student program to a file and try compiling it. If there are any errors, they get displayed and the process is aborted. Otherwise, and if it's not a precheck, I dynamically construct the tester (as a string) from the student program plus all the tests, write the string to a file, and compile and run that.
I'm not sure if it helps, but here's my Python get_test_cases function from one of my standard templates, whereTestCase is a class that wraps the test info. This function gets all the test data into an array of TestCase objects for use within a template grader - for simpler applications all you need is just the array of testcodes, probably.
def get_test_cases(): """Return an array of Test objects from the template parameter TESTCASES""" test_cases = [] {% for TEST in TESTCASES %} testcode = """{{ TEST.testcode | e('py') }}\n""" stdin = """{{ TEST.stdin | e('py') }}\n""" extra = """{{ TEST.extra | e('py') }}\n""" expected = """{{ TEST.expected | e('py') }}\n""" display = """{{ TEST.display | e('py') }}\n""" hiderestiffail = """{{ TEST.hiderestiffail | e('py') }}\n""" mark = {{ TEST.mark }} useasexamplestring = """{{ TEST.useasexample | e('py')}}""" useasexample = useasexamplestring not in ['', '0'] # Tricky! Empty during validation. testtype = {{ TEST.testtype }} test_cases.append(TestCase(testcode, stdin, extra, expected, display, hiderestiffail, mark, useasexample, testtype)) {% endfor %} return test_cases
However, you may think that's too complicated. You ask "Is there something in Twig that would allow me to selectively include student_answer perhaps?". Certainly you could use a Twig if statement that tests the IS_PRECHECK template parameter to conditionally include the test data with the student program. Something like
{% if not IS_PRECHECK %} {% for TEST in TESTCASES %} { {{ TEST.testcode }}; {% if not loop.last %} System.out.println(SEPARATOR); {% endif %} } {% endfor %} {% endif %}
I'm not sure if that answers your question or not. Feel free to try again if I've missed the point.
Richard
Thank you again Richard...
This seems to be what I was looking for:
{% if not IS_PRECHECK %}
{# include the student's code #}
{{ STUDENT_ANSWER | replace({'public class ': 'class '}) }}
{% endif %}
Happy days - on to the next problem :-)
Regards,
Anton