On this page:
4.1 Basic Test Syntax
4.2 Code Blocks
4.3 Test Statements
require:
header:
test:
4.4 Running Resyntax Tests

4 Testing Refactoring Rules🔗ℹ

 #lang resyntax/test package: resyntax

The resyntax/test language provides a convenient domain-specific language for testing refactoring rules. This language makes it easy to write comprehensive tests that verify refactoring rules work correctly across a variety of inputs, and that they properly handle edge cases without making unwanted transformations.

4.1 Basic Test Syntax🔗ℹ

Tests are written using #lang resyntax/test and consist of a series of test statements. Each statement begins with a keyword followed by a colon, and the statement’s body follows. Strings of code are written using code blocks. Here’s a simple example:

#lang resyntax/test

 

require: my-rules my-suite

 

header:

- #lang racket

 

test: "my rule transforms code as expected"

- (old-pattern 1 2 3)

- (new-pattern 1 2 3)

4.2 Code Blocks🔗ℹ

A code block is a delimited section of Racket code used within test statements. There are two types of code blocks:

  • Single-line code blocks are preceded by a single dash and a space (- ).

  • Multi-line code blocks are delimited by lines of at least three consecutive dashes (---). As a convenience, two adjacent multi-line code blocks can be separated by a single line of equals signs (===) instead of two lines of dashes.

Code blocks are essentially string literals, and can contain code written in any language. For this reason, it’s common for Resyntax tests to include a header: test statement which specifies what #lang each code block in that file is written in.

4.3 Test Statements🔗ℹ

The resyntax/test language supports three types of test statements:

test statement

(require: module-path suite-name)

Loads the refactoring suite named suite-name from the module at module-path. The refactoring suite will be used in all tests defined in the surrounding file. Multiple require: statements can be used to test rules from multiple different suites.

#lang resyntax/test

 

require: resyntax/default-recommendations list-shortcuts

require: my-custom-rules my-suite

test statement

(header: code-block)

Defines a code block that will be prepended to every test case in the file. This is useful for require statements and other common setup code that all tests need.

#lang resyntax/test

 

header:

--------------------

#lang racket/base

(require racket/list)

--------------------

test statement

(test: description-string test-body ...)

Defines a test case with the given description-string. The test-body consists of one or more code blocks. The number of code blocks determines what the test checks. If two code blocks are provided, the test case checks that Resyntax refactors the first block into the second:

#lang resyntax/test

 

test: "should rewrite old function to new function"

--------------------

#lang racket

(old-function 1 2 3)

====================

#lang racket

(new-function 1 2 3)

--------------------

If more than two code blocks are provided, the last code block is the desired code and the test case checks that Resyntax refactors each of the preceding code blocks into the desired code:

#lang resyntax/test

 

test: "should remove old-condition from and expressions"

- (and old-condition x)

- (and x old-condition)

- (and old-condition x old-condition)

- x

When only a single code block is provided, the resulting test checks that Resyntax does not make any changes to the code block:

#lang resyntax/test

 

test: "should not rewrite old function to new function in higher-order uses"

--------------------

#lang racket

(map old-function (list 1 2 3))

--------------------

4.4 Running Resyntax Tests🔗ℹ

Tests written in resyntax/test are integrated with RackUnit and can be run using the standard raco test command:

% raco test my-rule-test.rkt

raco test: (submod "my-rule-test.rkt" test)

5 tests passed

Each test: statement becomes a RackUnit test case, and the entire test file becomes a module with a single submodule named test. Clicking the Run button in DrRacket will execute each test in the file. Just like in RackUnit, failing tests are highlighted by DrRacket and print failure messages.

When executing tests, the resyntax/test language enables Resyntax’s debug logging and captures all of its logs. Failing test cases include the captured Resyntax logs in their printed output. This output can be somewhat verbose, but it makes it much easier to tell why Resyntax did or didn’t refactor code and how Resyntax came to produce a malformed suggestion.