"Mistakes are not errors but partially correct solutions with underlying logic." - Alina Tugend
An exercise's submission correctness test (SCT) is code that course creators write to check the correctness of a learner's code submission and guide them to the right solution.
When a learner runs their solution to an exercise, your SCT has access to the variables, functions, and objects within that code at runtime. Course creators can then use these constructs to determine whether or not a learner's submission should pass or fail.
Submission tests run in the same environment as a learner's submitted code. This means that when you write a function in the Submission Correctness Test editor box in the Course Creation Tool, you are automatically inside a submission test function and have access to the scope of that function.
Failing or passing a submission is determined by the return value from your
test function.
Return
Boolean true
to pass a learner's submission,
and return a
false
value to fail a learner's submission.
For example, if you want the learner's submission to always pass, return true.
return true;
If you return false, students will see the error message "Oops, try again." To provide a more helpful error message, return a string that will be displayed as an error.
return "Make sure that you have closed all your parentheses.";
The submission correctness test provides you with access to information regarding the code the learner has written and the status of the environment in which it was run. This information can be accessed and manipulated as follows:
The variable
code
contains the string of the entire contents of the code that the learner entered. For example, if you're expecting the submitted code to have at least one plus (+) sign, you could write the correctness test:
return code.indexOf('+') > -1;
The variable
result
contains the result of evaluating the students' code. It can be of any data type. If you're anticipating the result of a learner's entry to be a number, you could use the test:
return typeof result === "number";
If you're expecting the number two you could simply use:
return result === 2;
This test would work fine if the learner enters the expected code e.g.
1 + 2.
But what if the learner enters a single number. The submission test would pass it even though it's wrong.
We could further strengthen the test by adding the plus check:
return typeof result === "number" && code.indexOf('+') > -1;
That's better and it works. However its not 100% right. You could always write RegExp but then it may not catch all cases. The correct way to do it is to use a proper code analysis tool. Helpers for this type of check will be available in our library soon!
The error object contains the error thrown by a learner's code. If there is no error, it is the null object. This is useful when anticipating learner mistakes.
For example, if you wanted to test whether or not the learner's code threw a reference error, you could use:
if (error instanceof ReferenceError) {
return "Make sure you put quotes around your name."
}
You can also use regular expressions to check for specific strings in learner code. This is fairly rigid as a test, difficult to get just right, and is difficult to read. We don't recommend it, but it is useful in some cases.
For example, it is currently the only way to check if tags are closed in HTML.
if (code.html.match(/\<\/a\>/)===null) {
return 'Did you remember to close the "a" tags?';
}
return true;
In an effort to provide as rich an experience as possible to course creators, we have in addition to providing course creators with access to the aforementioned variables provided a suite of functions to make it easier to access various aspects of the runtime environment.
Say you ask the user to define a function called foo and to call said function. You could write a submission test like this:return typeof foo === "function" && code.match(/foo\s*\(/) != null;
Although this is a relativaly strong check, it could go wrong in many ways and is unneccessarily complex. To simplify such a check, use the CC.calls() function to test if a function has been defined and invoked within the user's code submission.
return typeof foo === "function" && CC.calls('foo').length > 0;
CC is our helper library's namespace (short for CodeCademy). We maintain the same API for all languages supported by our system unless mentioned otherwise.
CC.calls |
A function that takes a function name and returns an array of the arguments that were passed to the function every time it was called in the code. Student code:
Then by calling:
In our submission test would return an array looking like |
CC.methods |
A function that takes a method name and an object and returns an array of arguments that were passed to the method called on that object. Student code:
Then by calling:
In the SCT, we'd get an array looking like |
CC.equals |
Takes any number of objects and checks the deep equality of these objects. This is equivalent to calling JSON.stringify on each item and comparing the resulting strings.
|
CC.prints |
Returns an array of strings printed to the console. Student Code:
|
CC.printed |
Given a string, returns a boolean representing whether or not the string was printed to the console. Student code:
|
You can provide students with custom error messages from within the submission test by returning a string.
Lets go back to the addition example and further enhance it by giving the user hints about what they did wrong.
if (typeof result !== "number")
return "You should probably use numbers";
if (code.indexOf('+') === -1)
return "Maybe you should use the plus sign for addition"
return true
You can also try to guess what the learner did wrong from the type of error thrown from evaluating her code.
For example if your trying to get her to type in her name and got a reference error then chances are she left out the quotes:
if (error && error instanceof ReferenceError) {
return "Make sure you surround your name with quotes!"
}
if (typeof result === "string") {
return true;
}
return false;
Preview Mode adds an in-browser deubgging console that will show helpful log and error messages. Preview Mode console will show the following:
Errors in the SCT.
In web courses, errors from the learner code.
When SCT is waiting on an async event and when its resolved.
Thoroughly test your submission test functions before publishing your course.
Submission tests run in the same environment as a learner's submitted code. This means that when a student runs his or her code in an exercise, your SCT has access to all variables, functions, and objects within that code at runtime.
You can simply write SCTs to assume that those constructs exist. If the learner failed
to use the necessary construct, however, your SCT will have to handle the
generated exception appropriately (see
Helpful Error Messages
). Failure to handle the exception will result in the generic message:
Oops, try again.
Failing or passing a learner's submission is determined by the
return
value from your SCT. Return
true
to pass a learner's submission, and return a
false
value to fail a learner's submission.
For example, if you want the learner's submission to always pass, then your SCT can contain the following:
return true
If you simply return false, then students will see the error message:
"Oops, try again."
To provide a more helpful error message, you can return a string that will be displayed as the
error message. This can be achieved with the following:
return "Make sure to use the .each method in your code."
Of course, these types of SCTs are not very helpful, since they don't really check that the user's code works. You should avoid writing SCTs that only contain the above snippets. In the next section, we'll cover how to access constructs within a learner's submitted code.
The SCT provides you with access to information regarding the learner's code and the status of the environment in which it was run. This information can be accessed and manipulated by utilizing the following:
The
code
variable contains a string representation of the learner's submission. You can perform checks
against this variable to determine if the user's code contained the necessary operators.
For example, if the learner were to run the code:
my_sum = 2 + 2
Then the variable
code
would contain the string
"mysum = 2 + 2"
If you wanted to make sure that the addition operator
+
was used, you could simply check that the code contains more than 0 instances of the addition operator,
This can be achieved with the following:
return code.include? "+"
Remember,
code
is just a string variable, so you can use Ruby's built-in string methods to determine if the student's code solves the exercise.
The above code uses Ruby's
#include?
method to determine how many times the string
"+"
occurs in the student's code.
You might think to use the
code
variable for checking if a necessary variable was declared in the learner's code, but it might be more appropriate to
assume that the variable exists and try calling it. If the learner didn't define the required variable, then your SCT
will trigger a
NameError
exception.
See the section
Helpful Error Messages
for a discussion of handling exceptions with Ruby's
begin/rescue/end
constructs.
The variable
result
contains the result of evaluating the students' code. If you'd like to make sure that the result
of a learner's submission is an integer, you could use the following in your SCT:
return result.is_a? Integer
If you're expecting the evaluation of the student's code to be a specific value, you could then use the following:
return result == 4
Again, this holds for any data type, not just integers.
The problem is that if you only check that the answer is correct, you allow the learner to just simply enter
the answer and hit "run." Unfortunately, your SCT will pass them. Instead, if you want ensure that an operation be used to
yield the answer, you can use the
code
variable in conjunction with the
result
variable. This can be seen from the following:
return code.include? "+" && result == 4
The above SCT ensures that the student's code produces the answer 4 and includes an addition operation. However, this is still not perfect. This SCT will pass the user given the following incorrect code:
fooled_you = 100 + 50
4
This passes because it satisfies the fact that the result was the number 4 (from the second statement) and that the code contained at least one use of the addition operator. The correct way to do it is to use a proper code analysis tool. Helpers for this type of check will be available soon!
The
exception
object contains the exception thrown by a student's code. If there is no exception, its value is
nil
. This is useful when anticipating student mistakes.
For example, the following student code generates a SyntaxError exception:
my_name = "Eric Weinstein
In your SCT, you can handle syntax errors with the following:
if error.kind_of? SyntaxError
return "Make sure to use double quotes around your name."
This shows the following output to the learner:
Oops, try again.
Make sure to use double quotes around your name.
This is discussed further in the section Helpful Error Messages .
We've provided you with a suite of functions to make it easier to
check various aspects of a learner's submission. These functions are contained within
codecademy_lib
, also known as the
CC
library.
For Ruby, this library is still under development. We'll incorporate additional helper methods soon!
prints |
Returns an array of strings that were printed to the console after running the learner's code.
You do not need to prefix
Student Code:
SCT:
|
printed |
A separate
Given a string,
Student code:
SCT:
Note that this
will not
work for the totality of the student's printed output, as
|
It's important to understand that SCTs are meant not only to check the correctness of a student's code, but to help guide him or her to the right answer(s). Many students get discouraged when the console prints unhelpful or confusing error messages. Hence, it's your job to avoid those obstacles and provide encouraging and useful messages for likely errors.
You can provide students with custom error messages from within the submission test by returning a string.
In the simple case, if the learner's solution doesn't contain required constructs, you can return a string that explains why their solution is incorrect.
For example, let's go back to the addition example and further enhance it by giving the learner hints about what they did wrong.
unless result.is_a? Integer
return "Check to make sure your code results in an integer."
unless code.include? "+"
return "It doesn't look like you're using the addition operator."
return true
Rather than using
if !true
in Ruby, it's often cleaner to use
unless true
. However, this construct should be avoided if the statement includes an
else
. In that case,
if / else
is the better construction.
It's important to note that errors can appear both in the user's code and the SCT.
Errors in the student's code can typically be found in the
exception
variable, as discussed in the
Accessing Student Code
section. You can check for these errors using a simple conditional check and return a message
that helps the student understand how they generated an error.
Errors in your SCT can result from two situations: a syntax error in your code or an exception generated when trying to use constructs defined in the user's code.
For the first type of SCT error, where your code is flawed, those errors are reported to you via the preview mode console discussed in the Debugging and Preview Mode section. These errors should be straightforward for you to remedy.
The second type of SCT error, where your SCT uses non-existent constructs in the student's code,
generates exceptions that you need to handle using Ruby's
begin/rescue/end
syntax.
For example, if your exercise asked the user to type in his or her name and the submission generated a syntax error, it's very likely that the student missed a starting or closing quote:
if exception.kind_of? SyntaxError
return "Make sure you surround your name with quotes!"
unless result.is_a? String
return "Make sure your code produces a string value."
return true
Raised when a variable is used in a context but not declared. This exception can be triggered form both the user's code and the SCT.
puts first_name # first_name not declared
The SCT to catch this:
if exception.kind_of? NameError
return "It looks like you tried to use a variable without declaring it first."
If the exercise called for a variable
first_name
to be defined and the student's code was:
"Oxnard Montalvo"
The following SCT will attempt to use the expected variable
first_name
only to see that it doesn't exist, triggering a
NameError
exception
within the SCT.
first_name == 'Ryan' # NameError
The SCT to catch this exception involves wrapping the SCT code in a
begin/rescue/end
block:
begin
first_name # NameError
rescue NameError:
return "Did you remember to declare a variable called first_name?"
end
# If they don't trigger an exception, let's pass them.
return true
The learner will then see the following output:
Oops, try again.
Did you remember to declare a variable called first_name?
Raised when the student generates any kind of syntax error. This exception should be caught
using the
exception
variable, and error messages should be context-dependent. For instance, if the student is learning how to use
if/else
statements and his or her code raises a syntax error, your SCT might be:
if exception.kind_of? SyntaxError
return "It looks like your if/else syntax isn't quite right."
Raised when the denominator of a division or modulo operation is zero. This exception should be
caught using the
exception
variable.
Student Code:
100 / 0
SCT to catch this:
if exception.kind_of? ZeroDivisionError
return "Dividing by zero isn't allowed!"
Preview Mode adds an in-browser debugging console that will show helpful log and error messages. This mode is activated when you hit Save and then Preview when editing an exercise. You'll then notice a console window at the bottom of the page.
The Preview Mode console will show you the following:
Errors in your SCT generated from syntax and other creator-caused errors.
When the SCT is waiting on an asynchronous event and when it's resolved.
When a student attempts to solve an exercise that has a flawed SCT, the student shouldn't be blocked from progressing through the course. To this end, we've instated logic such that broken SCTs will automatically pass the student.
Please thoroughly test all submission correction tests before publishing your course!
Submission tests run in the same environment as a learner's submitted code. This means that when a learner runs their code in an exercise, your SCT has access to the variables, functions, and objects within that code at runtime.
You can simply write SCTs to assume that those constructs exist. If the learner failed
to use the necessary construct, however, your SCT will have to handle the
generated exception appropriately (see
Helpful Error Messages
). Failure to handle the exception will result in the generic message:
Oops, try again.
Failing or passing a learner's submission is determined by the return value from your SCT.
Return
True
to pass a learner's submission,
and return a
False
value to fail a learner's submission.
For example, if you want the learner's submission to always pass, then your SCT can contain the following:
return True
If you simply return false, then students will see the error message:
"Oops, try again."
To provide a more helpful error message, you can return a string that will be displayed as the
error message. This can be achieved with the following:
return "Please check that you have closed all of your parentheses."
Of course, these types of SCTs are not very helpful, since they don't really check that the user's code works. You should avoid writing SCTs that only contain the above snippets. In the next section, we'll cover how to access constructs within a learner's submitted code.
The submission correctness test provides you with access to information regarding the learner's code and the status of the environment in which it was run. This information can be accessed and manipulated by utilizing the following in your SCTs:
The
code
variable contains a string representation of the learner's submission. You can perform checks against this variable to determine
if the user's code contained the necessary operators.
For example, if the learner ran the code:
my_sum = 2 + 2
Then the variable
code
would contain the string
"mysum = 2 + 2"
If you wanted to make sure that the addition operator
+
was used, they could simply check that the code contains more than 0 instances of the addition operator.
i.e., The code should contain at least one instance of the addition operator.
This can be achieved with the following:
return code.count("+") > 0
Remember,
code
is just a string variable, so you can use Python's built-in string methods to determine if the learner's code solves the exercise.
The above code uses Python's
count()
function to determine how many times the string
"+"
occurs in the learner's code.
You might think to use the
code
variable for checking if a necessary variable was declared in the learner's code, but it might be more appropriate to
assume that the variable exists and try calling it. If the learner didn't define the required variable, then your SCT
will trigger a
NameError
exception.
See the section
Helpful Error Messages
for a discussion of handling exceptions with Python's
try/except
constructs.
The variable
result
contains the result of evaluating the students' code. It can be of any data type. If you'd like to make sure that the result
of a learner's submission is an integer, you could use the following in your SCT:
return type(result) == int
If you're expecting the evaluation of the learner's code to be a specific value, you could then use the following:
return result == 2
Again, this holds for any data type, not just integers.
The problem is that if you only check that the answer is correct, you allow the learner to just simply enter
the answer and hit run. Unfortunately, your SCT will pass them. Instead, if you want ensure that an operation be used to
yield the answer, you can use the
code
variable in conjunction with the
result
variable. This can be seen from the following:
return result == 2 and code.count('+') > 0
The above SCT ensures that the learner's code produces the answer 2 and has an addition operation. However, this is still not perfect. This SCT will pass the user given the following incorrect code:
fooled_you = 100 + 50
2
This passes because it satisfies the fact that the result was the number 2 (from the second statement) and that the code contained at least one use of the addition operator. The correct way to do it is to use a proper code analysis tool. Helpers for this type of check will be available soon!
The
error
object contains the exception thrown by a learner's code. If there is no error, its value is
None
. This is useful when anticipating learner mistakes.
For example, the following learner's code generates a SyntaxError exception:
name = "Joel Kemp
In your SCT, you can handle syntax errors with the following:
if type(error) == SyntaxError:
return "Make sure that you have double quotes around your name."
This shows the following output to the learner:
Oops, try again.
Make sure that you have double quotes around your name.
This is discussed further in the section Helpful Error Messages .
We've provided you with a suite of functions to make it easier to
check various aspects of a learner's submission. These functions are contained within
codecademy_lib
, also known as the
CC
library.
For Python, this library is still in development and we will incorporate additional helper methods soon.
prints |
Returns an array of strings that were printed to the console after running the learner's code. Student Code:
SCT:
|
printed |
Given a string, the
Student code:
SCT:
|
It's important to understand that SCTs are meant to guide students to the right answers, in addition to checking the correctness of their code. Many students get discouraged when the console prints uninformative errors. Hence, it's your job to avoid those obstacles and provide encouraging messages for likely errors.
You can provide students with custom error messages from within the submission test by returning a string.
In the simple case, if the learner's solution doesn't contain required constructs, you can return a string that explains why their solution is incorrect.
For example, let's go back to the addition example and further enhance it by giving the learner hints about what they did wrong.
if type(result) != int:
return "Check to make sure that you're using numbers."
if code.count('+') == 0:
return "It doesn't seem like you're using the addition operator."
return True
It's important to note that errors can be generated from both the user's code and the SCT.
Errors in the learner's code can typically be found in the
error
variable, as discussed in the
Accessing Student Code
section. You can check for these errors using a simple conditional check and return a message
that helps the learner understand how they generated an error.
Errors in your SCT can result from two situations: a syntax error in your code or an exception generated when trying to use constructs defined in the learner's code.
For the first type of SCT error, where your code is flawed, those errors are reported to you via the preview mode console discussed in the Debugging and Preview Mode section. These errors should be straightforward for you to remedy.
The second type of SCT error, where your SCT uses non-existent constructs in the learner's code,
generates exceptions that you need to handle using Python's
try/except
syntax.
For example, if your exercise asked the learner to type in their name and their submission generated a syntax error, then it's very likely that the learner missed a starting or closing quote:
if error and type(error) == SyntaxError:
return "Make sure you surround your name with quotes!"
if type(result) == str:
return True
return False
Raised when a variable or function is used in a context but not declared/defined. This exception can be triggered form both the learner's code and the SCT.
name = first_name #first_name not declared
The SCT to catch this:
if type(error) == NameError:
return "You tried using a variable that doesn't exist."
If the exercise called for a variable
first_name
to be defined and the learner's code was:
"Bob"
The following SCT will attempt to use the expected variable
first_name
only to see that it doesn't exist -- triggering a
NameError
exception
within the SCT.
print "Welcome", first_name # NameError
The SCT to catch this exception involves wrapping the SCT code in a
try/except
block:
try:
print "Welcome", first_name # NameError
except NameError:
return "Make sure that you've defined the variable first_name."
# If they don't trigger an exception, then let's pass them.
return True
The learner will then see the following output:
Oops, try again.
Make sure that you've defined the variable first_name.
Raised when the denominator of a division or modulo operation is zero. This exception should be
caught using the
error
variable.
Student Code:
2 / 0
SCT to catch this:
if type(error) == ZeroDivisionError:
return "Dividing by zero is not allowed."
Preview Mode adds an in-browser debugging console that will show helpful log and error messages. This mode is activated when you hit Save and then Preview when editing an exercise. You'll then notice a console window at the bottom of the page.
The Preview Mode console will show you the following:
Errors in your SCT generated from syntax and other creator-caused errors.
When the SCT is waiting on an async event and when its resolved.
When a learner attempts to solve an exercise that has a flawed SCT, the learner shouldn't be blocked from progressing through the course. To this end, we've enstated that broken SCTs will automatically pass the learner.
Please thoroughly test your submission correction tests before publishing your course.
Submission tests run in the same environment as a learner's submitted code. This means that when you write a function in the Submission Correctness Test editor box in the Course Creation Tool, you are automatically inside a submission test function and have access to the scope of that function.
Failing or passing a submission is determined by the return value from your
test function.
Return
Boolean true
to pass a learner's submission,
and return a
false
value to fail a learner's submission.
For example, if you want the learner's submission to always pass, return true.
return true;
If you return false, students will see the error message "Oops, try again." To provide a more helpful error message, return a string that will be displayed as an error.
return "Make sure that you have closed all your parentheses.";
The submission correctness test provides you with access to information regarding the code the learner has written and the status of the environment in which it was run. This information can be accessed and manipulated as follows:
The variable
code
contains the string of the entire contents of the code that the learner entered. For example, if you're expecting the submitted code to have at least one plus (+) sign, you could write the correctness test:
return code['script.js'].indexOf('+') > -1;
Notice that unlike when accessing code in a JavaScript lesson we have to tell the code descriptor which file we want it to look in. Here We noted that we wanted to look in the file ['script.js'].
You can also use regular expressions to check for specific strings in learner code. This is fairly rigid as a test, difficult to get just right, and is difficult to read. We don't recommend it, but it is useful in some cases.
For example, it is currently the only way to check if tags are closed in HTML.
if (code['script.js'].match(/\<\/a\>/)===null) {
return 'Did you remember to close the "a" tags?';
}
return true;
In an effort to provide as rich an experience as possible to course creators, we have provided a suite of functions to make it easier to access various aspects of the runtime environment.
Say you ask the user to define a function called foo and to call said function. You could write a submission test like this:
return typeof foo === "function" && code.match(/foo\s*\(/) != null;
Although this is a relativaly strong check, it could go wrong in many ways and is unneccessarily complex. To simplify such a check, use the CC.calls() function to test if a function has been defined and invoked within the user's code submission.
return typeof foo === "function" && CC.calls('foo').length > 0;
CC is our helper library's namespace (short for CodeCademy). We maintain the same API for all languages supported by our system unless mentioned otherwise.
CC.calls |
A function that takes a function name and returns an array of the arguments that were passed to the function every time it was called in the code. Student code:
Then by calling:
In our submission test would return an array looking like |
CC.equals |
Takes any number of objects and checks the deep equality of these objects. This is equivalent to calling JSON.stringify on each item and comparing the resulting strings.
|
CC.prints |
Returns an array of strings printed to the console. Student Code:
|
CC.printed |
Given a string, returns a boolean representing whether or not the string was printed to the console. Student code:
|
You can provide students with custom error messages from within the submission test by returning a string.
Lets go back to the addition example and further enhance it by giving the user hints about what they did wrong.
if (typeof result !== "number")
return "You should probably use numbers";
if (code.indexOf('+') === -1)
return "Maybe you should use the plus sign for addition"
return true
You can also try to guess what the learner did wrong from the type of error thrown from evaluating her code.
For example if your trying to get her to type in her name and got a reference error then chances are she left out the quotes. You have 2 common options if you have to check a variable value, and so cannot use the $expect.js library to check a DOM element. You can use a try catch statement in anticipation of an error:
try
{
if (typeof sampleVariable === "string") {
return true;
}
catch(err)
{
return "sampleVariable did not exist! Make sure it is being initialized.";
}
This method is more robust and allows you to check any operation you perform. However, if all you are checking is an if statement, then you can use this method as well:
if(typeof sampleVariable == "undefined" || sampleVariable != 4)
return "You did not correctly set sampleVariable to 4. Please make sure your code correctly gives it a value";
This works because if the first check in the if statement finds that sampleVariable is indeed undefined, it will skip the second check and jump directly into the if clause. This behaviour within JavaScript allows us to avoid the second check for a nonexistant variable. Back to top
Preview Mode adds an in-browser debugging console that will show helpful log and error messages. Preview Mode console will show the following:
Errors in the SCT.
Errors from the learner code.
When SCT is waiting on an async event and when its resolved.
Thoroughly test your submission test functions before publishing your course.