IDE Test Feedback for MoodleA VS Code extension that runs your project's unit tests and submits the results to Moodle. It detects the test framework, runs the suite, and posts a structured run to your course's submission service — authenticated with your Microsoft (Entra ID) account. Features
Setup
|
| Command | What it does |
|---|---|
| IDE Test Feedback: Run Tests & Submit to Moodle | Detect, run, parse, and submit. |
| IDE Test Feedback: Run Tests (No Submit) | Detect, run, and parse only. |
| IDE Test Feedback: Sign In with Microsoft | Start a Microsoft auth session. |
| IDE Test Feedback: Sign Out | Explains how to remove the account from the Accounts menu. |
| IDE Test Feedback: Configure Assignment | Set the service URL and the project's assignment key. |
| IDE Test Feedback: Show Log | Reveal the output channel. |
What gets submitted
Each run posts the results and the test files that produced them. Per test:
testSuite,testName,status,durationMs, and the failuremessagesource— where the test lives: its file path relative to the workspace folder, and the line range of its declaration. When a test can't be matched to a declaration onlypathis sent; when the file can't be found at all,sourceis omitted and only the framework's own report is sent.
Alongside the results, testFiles carries each test file once — its workspace-relative
path and its contents. A test's code is read by slicing its line range out of its file, so no
test body is sent twice, and imports, fixtures and setup methods come along with it. With
capture off, or once the size budget is spent, a file is listed without its content.
Deliberately not submitted: raw stack traces, absolute file paths (a path outside the
workspace folder is reduced to its filename), and anything about your machine or account
beyond the identity in your sign-in token. Paths inside a failure message are cleaned the same
way: one inside the project becomes relative, and any other path in your home folder starts
with ~. Paths outside your home folder are sent unchanged.
One flag is sent alongside the results, and only when it applies:
captureDisabled— you switched source capture off. Without it, a submission with no code would be indistinguishable from one where the extension couldn't find your sources.
The pre-submit check is local
The extension checks your tests for empty bodies, missing assertions and skip markers such
as @Disabled or @pytest.mark.skip, and warns you before submitting if a run looks
degraded. The findings stay on your machine — nothing about the check is submitted,
including whether the warning was shown. It's there to catch a test you accidentally
emptied or left disabled.
It never blocks a submission, and it can be switched off with
ideTestFeedback.warnOnSuspiciousTests — which silences the dialog but does not change what
is sent.
What your instructor reads is the test code itself, which is the thing worth reading.
For the gateway and Moodle plugin
testFiles[].content carries code verbatim, including < and > (List<String>,
Assert.Throws<T>). It must be declared PARAM_RAW on the Moodle side — running it
through PARAM_TEXT would strip those via strip_tags. The extension does sanitize
testSuite, testName and message for PARAM_TEXT, since those are display fields.
Join a result to its file with source.path == testFiles[].path, then slice
startLine..endLine (1-based, inclusive) out of content. Content is LF-normalized, and a
truncated file is cut at a character boundary, so line numbers still hold for what remains.
The extension keeps to the gateway's validation limits before sending: an assignmentKey
of at most 100 characters from [A-Za-z0-9_-], at most 5000 results and 200 test files,
and the @Size limits on each text field. Past 200 files, the files are kept in path order
and the results whose file was left out are sent with no source, so every source.path
always has a matching testFiles entry.
Settings
Settings cover your machine and preferences; what the assignment is lives in
.ide-test-feedback.json.
Connection — user settings only. A project's .vscode/settings.json cannot set these, so a
cloned repository can't redirect where your sign-in token is sent.
| Setting | Default | Description |
|---|---|---|
ideTestFeedback.serviceUrl |
"" |
Base URL of the submission service. |
ideTestFeedback.authScopes |
["User.Read"] |
OAuth scopes requested from the Microsoft provider. Change only for a different deployment. |
ideTestFeedback.requestTimeoutMs (default 15000, clamped to 1 000–120 000) sets the timeout for
requests to the service. It changes nothing about where the token goes, so a workspace may set it too.
Running tests — can differ per folder.
| Setting | Default | Description |
|---|---|---|
ideTestFeedback.preferredAdapter |
– | Force maven-junit, gradle-junit, pytest, or dotnet-test instead of auto-detecting. |
ideTestFeedback.testCommandOverrides |
{} |
Per-adapter command overrides, e.g. { "maven-junit": "mvn -Pci test" }. |
Source capture — can differ per folder.
| Setting | Default | Description |
|---|---|---|
ideTestFeedback.submitTestSource |
true |
Submit the source of each test. Turning this off still submits where each test was found. |
ideTestFeedback.maxTotalSourceChars |
500000 |
Cap on the source captured per submission (at most 1 000 000). |
ideTestFeedback.warnOnSuspiciousTests |
true |
Warn before submitting when tests look emptied or disabled. Never blocks. |
Workspace trust
Running tests executes the project's own build and test code, so the extension is disabled in Restricted Mode. Trust the folder to use it.
Supported test frameworks
| Adapter | Detected by | Default command |
|---|---|---|
| Maven (JUnit) | pom.xml |
mvnw -B test -Dmaven.test.failure.ignore=true (or mvn …) |
| Gradle (JUnit) | build.gradle(.kts) / settings.gradle(.kts) |
gradlew cleanTest test --continue (or gradle …) |
| pytest | pytest.ini, pyproject.toml, setup.cfg, conftest.py, or test_*.py / *_test.py files |
python -m pytest --junit-xml=… |
| .NET | *.csproj / *.sln / *.slnx, or a *Test.csproj / *Tests.csproj one folder down |
dotnet test --logger trx … |
The project's own Maven or Gradle wrapper is used when it has one; otherwise mvn or
gradle must be on your PATH. pytest runs with the Python in the project's .venv,
venv or env folder if there is one, and otherwise with python3 (py -3 or python
on Windows). dotnet must be on your PATH. A run that produces zero results is
reported as an error, since it almost always means the command itself failed to start.
Development
npm install
npm run watch # esbuild bundle in watch mode
npm run typecheck # tsc --noEmit
npm run lint
npm test # vitest
Press F5 to launch the Extension Development Host. npm run package
produces the production bundle; npx vsce package builds a .vsix.