On this page:
4.1 Basic Test Syntax
4.2 Code Blocks
4.3 Test Statements
require
header
test
no-change-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 four 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 code block in the file. This is useful for common setup code that all tests need, such as a #lang line or library imports.

#lang resyntax/test

 

header:

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

#lang racket/base

(require racket/list)

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

test statement

(test description-string
      input-code-block ...+
      expected-code-block)
Defines a test case named with the given description-string. The test case checks that Resyntax refactors each input-code-block block into the final expected-code-block:

#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)

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

 

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

- (and old-condition x)

- (and x old-condition)

- (and old-condition x old-condition)

- x

test statement

(no-change-test description-string input-code-block)

Defines a test case named with the given description-string. The test checks that Resyntax does not make any changes to the input-code-block:

#lang resyntax/test

 

no-change-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.