The SCT (Submission Correctness Test) sheet holds all the information necessary to test an exercise solution. We developed a designated language in order to express what you want to test for each exercise, called sheetwhat. If you've built R or Python courses for DataCamp before, you might recognize elements from testwhat or pythonwhat in this language. Unlike with R or Python courses, instructors are responsible for writing the SCTs for spreadsheet courses. 

There's a whole section on how to write SCTs, but here's an example of how a simple SCT could look:

The following naming convention should be used for the SCT sheet: Exercise <exercise number> - SCT .

A few things you can already notice here are:

  • An SCT is defined in a certain cell. This means the check will be done on this cell in the user's solution. Specifically in our example, the value in F2  will be checked.
  • An SCT starts with Ex() , followed by a dot and the SCT itself. If there are multiple SCTS in a cell, they all start on a separate line and each line starts with Ex() . Note that one SCT can cover multiple lines. An example SCT could be:
Ex().has_equal_formula(
    incorrect_msg="Alas! The formula is not correct."
)
Ex().has_equal_value()
  • All SCT functions (unless defined otherwise in the specific function's documentation) will compare a value in the user's sheet with values in the solution. In our example, the value in F2  of the user's sheet is compared with the value in that cell in the solution sheet.
  • SCT functions can have arguments, but a lot of them can be used without any arguments.

SCT functions

Each SCT function can be used with zero or more arguments. It's advised to always use named arguments.

Ex().has_equal_value(incorrect_msg = "Something is wrong.")

If there are multiple arguments, separate them with a comma:

Ex().has_equal_references(
  absolute = True,
  incorrect_msg = "Something is wrong."
)

As you can see, whitespaces can be used between the parentheses at your own convenience. This doesn't change the meaning of the SCT.

String arguments

Although it's strongly advised to use the default feedback message, there are multiple SCTs that allow custom feedback messages. For most of those, you can use a template string where the SCT cell address will be filled in automatically. For example in:

Ex().has_equal_value(incorrect_msg = "Look at {sct_range}.")

will translate to "Look at F2." if used in cell F2 .

Additionally, you can use markdown notation in the string for formatting options. For example: 

Ex().has_equal_value(incorrect_msg = "**Look** at `{sct_range}`.")

will look as follows: "Look at F2 ." if used in cell F2 .

has_equal_value()

Ex().has_equal_value(
  incorrect_msg = string
)

Compares the calculated value at this cell with what's defined in the solution. There will be a margin of error that's allowed for numeric values.

Examples:

Ex().has_equal_value()
Ex().has_equal_value()(
  incorrect_msg = "The value is not correct at `{sct_range}`."
)

has_equal_formula()

Ex().has_equal_formula(
  incorrect_msg = string
)

Compares the formula of the user in this cell with what's defined in the solution. The formula will be normalised, meaning capitalisation and spaces won't matter.

Examples:

Ex().has_equal_formula()
Ex().has_equal_formula()(
  incorrect_msg = "The formula is not correct at `{sct_range}`."
)

has_code()

Ex().has_code(
  pattern = string,
  fixed = True | False (default: False),
  incorrect_msg = string
)

Checks a pattern in the user's cell content. Can be a string if fixed is True  or a regular expression otherwise. The non-calculated value will be compared with the regex. We're using Javascript flavoured regexes. This is a useful tool to test a regex. Make sure you're comfortable with regex before attempting to use this.

Note: for this SCT, the solution is not used

Example:

Ex().has_code(
  pattern = "1\.1\s*-\s*1",
  incorrect_msg = "Please subtract one from 1.1."
)

check_function()

check_function(
  name = string,
  missing_msg = string
)

Checks whether the user used a certain function. The functions are normalised, so capitalisation is not an issue. A more tailored feedback message will be automatically generated, so this function can be used without any specific missing_msg.

Note: for this SCT, the solution is not used

Example:

Ex().check_function(name = "SUM")

check_operator()

check_operator(
  operator = string,
  missing_msg = string
)

Checks whether the user used a certain operator. A more tailored feedback message will be used automatically, so this function can often be used without any specific missing_msg.

Note: for this SCT, the solution is not used

Example:

Ex().check_operator(operator = "+")

has_equal_references()

Ex().has_equal_references(
  absolute = True | False (default: False),
  incorrect_msg = string
)

Check whether the correct references are used in a cell. This function will compare the user's input to the solution. It will check whether all references that are used in the solution, are also used in the user's input. When absolute is True , absolute references will be matched instead of regular references. It can often be used without arguments.

Example:

Ex().has_equal_references()

has_equal_pivot()

Ex().has_equal_pivot()

Checks whether the pivot table defined by the user is the same as the one in the solution. The system tries to do smart checks so you don't have to use this SCT with arguments. It will generate a detailed feedback message automatically. Ex().has_equal_pivot() should be defined on the address of the upper-left corner of the pivot table in the solution.

To handle newly created pivot tables (i.e., not in "Sheet1"), Ex().has_equal_pivot() will look through all sheets to find the first sheet that contains a pivot table and does the checks on that sheet.

Example:

Ex().has_equal_pivot()

check_chart()

Ex().check_chart()

This function checks compares a chart in the solution's sheet to a chart in the user's sheet in "Sheet1". It finds the chart that has its upper left corner closest to the cell where the SCT is defined.

By itself, this SCT checks whether a chart is defined and that it's of the correct type. To do more specific tests, you can chain Ex().check_chart() with the following:

  • has_equal_title(): checks whether the chart has the same title as in the solution
  • has_equal_domain(): checks whether the X-axis is the same as in the solution
  • has_equal_series(): checks whether the series of the chart are the same as in the solution
  • has_equal_single_series(
      number = number,
      min_range_str = string,
      series_type = "source"
    )
    : checks whether the nth series, defined by number, at least contains the range defined in min_range_str. The last argument, series_type, is always "source" for now.

Example:

Ex().check_chart()
Ex().check_chart().has_equal_title()
Ex().check_chart().has_equal_domain()
Ex().check_chart().has_equal_single_series(
  number = 1,
  min_range_str = "A1:A5",
  series_type = "source"
)

has_equal_conditional_formats()

Ex().has_equal_conditional_formats()

Check whether the same conditional format rules are defined as in the solution in the cell where the SCT is defined.

Example:

Ex().has_equal_conditional_formats()

has_equal_number_format()

Ex().has_equal_number_format()

Check whether the same number formatting is used as in the solution in the cell where the SCT is defined.

Example:

Ex().has_equal_number_format()

check_correct()

Ex().check_correct(
  check = SCT,
  diagnose = SCT
)

This is the only meta SCT function. Ex().check_correct() accepts two arguments: check and diagnose and both of them are SCTs themselves. The SCTs in check  or diagnose  should not be preceded by Ex() .

The function will first check whether the SCT in check passes. If it passes, the SCT in diagnose is never executed and the SCT passes. If check fails, diagnose is ran and will generally give the user better feedback messages using this SCT.

 Ex().check_correct() is very useful in situations where you want to make a forgiving SCT, where you first check a value and only if that value is not correct, will run more specific SCTs. You'll often see the check being a simple has_equal_value() and the diagnose having functions like check_function(). This way we accept students arriving to the correct solution, without being obliged to use the exact same method as we expect them to do.

It's worth nothing here that diagnose often contains multiple SCT functions. If that's the case, we can group them by putting them in a multi  statement (multi(...)) and splitting them with commas.

Examples:

Ex().check_correct(
  check = has_equal_value(),
  diagnose = multi(
    has_equal_references(),
    check_function(function = "SUM")
  )
)
Ex().check_correct(
  check = has_equal_value(),
  diagnose = multi(
    check_operator(operator = "/"),
    has_equal_references(),
    has_equal_references(absolute = True)
  )
)

Did this answer your question?