How to Run Unit Tests and Capture Results in Batch Script
Automated testing is a cornerstone of reliable software development. Running unit tests from a Batch Script and capturing the results enables continuous integration workflows, pre-commit validation, build pipeline gates, and rapid feedback loops. Whether you are working with .NET, Java, Python, Node.js, or any other testing framework, a Batch Script can orchestrate test execution, collect results, and take action based on pass or fail outcomes.
In this guide, we will explore how to run unit tests from various frameworks and capture their results using Batch Script, including return code checks, output logging, and result parsing.
Understanding Test Exit Codes
Most test runners follow a standard convention:
| Exit Code | Meaning |
|---|---|
0 | All tests passed |
1 or non-zero | One or more tests failed |
2 | Test runner error (configuration, missing files) |
Batch scripts use %errorlevel% to capture the exit code after running the test command.
Method 1: Running .NET Tests (dotnet test)
@echo off
setlocal
set "project=MyApp.Tests"
:: Generate locale-safe timestamp for the log filename
for /f "tokens=2 delims==" %%T in ('wmic os get LocalDateTime /value') do set "dt=%%T"
set "logfile=test_results_%dt:~0,4%%dt:~4,2%%dt:~6,2%.log"
echo =============================================
echo RUNNING UNIT TESTS: %project%
echo %date% %time:~0,8%
echo =============================================
echo.
:: Run tests and capture output
dotnet test "%project%" --no-build --verbosity normal > "%logfile%" 2>&1
set "test_result=%errorlevel%"
:: Display results
type "%logfile%"
echo.
echo =============================================
if %test_result%==0 (
echo RESULT: ALL TESTS PASSED
) else (
echo RESULT: TESTS FAILED (exit code: %test_result%^)
)
echo Log: %logfile%
echo =============================================
exit /b %test_result%
Generating a TRX Report
dotnet test MyApp.Tests --logger "trx;LogFileName=results.trx" --results-directory TestResults
This creates an XML-based .trx report that can be consumed by CI/CD tools like Azure DevOps.
Method 2: Running Python Tests (pytest)
@echo off
setlocal
set "test_dir=tests"
set "logfile=pytest_results.log"
echo Running Python tests...
echo.
:: Run pytest with verbose output and JUnit XML
python -m pytest "%test_dir%" -v --tb=short --junitxml=test_report.xml > "%logfile%" 2>&1
set "test_result=%errorlevel%"
type "%logfile%"
echo.
if %test_result%==0 (
echo [PASSED] All tests passed.
) else (
echo [FAILED] Some tests failed. Exit code: %test_result%
)
exit /b %test_result%
Method 3: Running Node.js Tests (npm test)
@echo off
setlocal
set "logfile=npm_test_results.log"
echo Running Node.js tests...
echo.
:: npm test typically runs the "test" script from package.json
call npm test > "%logfile%" 2>&1
set "test_result=%errorlevel%"
type "%logfile%"
echo.
if %test_result%==0 (
echo [PASSED] All tests passed.
) else (
echo [FAILED] Tests failed. Exit code: %test_result%
)
exit /b %test_result%
Use call npm test (with call) in Batch scripts. Without call, the npm command terminates the Batch script after execution because npm.cmd is itself a Batch file.
Method 4: Running Java Tests (Maven)
@echo off
setlocal
set "logfile=maven_test_results.log"
echo Running Java unit tests...
echo.
call mvn test -B > "%logfile%" 2>&1
set "test_result=%errorlevel%"
:: Extract summary from Maven output
echo.
echo Test Summary:
findstr /i "Tests run:" "%logfile%"
echo.
if %test_result%==0 (
echo [PASSED] All tests passed.
) else (
echo [FAILED] Tests failed.
)
exit /b %test_result%
Method 5: Universal Test Runner with Result Capture
A generic test runner that works with any command and provides structured output:
@echo off
setlocal enabledelayedexpansion
:: Configuration
set "test_command=dotnet test MyApp.Tests --no-build -v normal"
set "project_name=MyApp"
set "log_dir=TestLogs"
:: Create log directory
if not exist "%log_dir%" mkdir "%log_dir%"
:: Generate timestamped log filename
for /f "tokens=2 delims==" %%T in ('wmic os get LocalDateTime /value') do set "dt=%%T"
set "timestamp=%dt:~0,4%%dt:~4,2%%dt:~6,2%_%dt:~8,2%%dt:~10,2%%dt:~12,2%"
set "logfile=%log_dir%\%project_name%_%timestamp%.log"
echo =============================================
echo TEST EXECUTION
echo Project: %project_name%
echo Command: %test_command%
echo Log: %logfile%
echo Started: %date% %time:~0,8%
echo =============================================
echo.
:: Record start time
set "start_time=%time%"
:: Execute tests (call ensures .cmd wrappers like npm/mvn don't terminate the script)
call %test_command% > "%logfile%" 2>&1
set "test_result=!errorlevel!"
:: Record end time
set "end_time=%time%"
:: Display results
echo.
echo =============================================
echo TEST RESULTS
echo =============================================
echo.
echo Exit Code: !test_result!
echo Started: %start_time%
echo Finished: %end_time%
if !test_result!==0 (
echo Status: PASSED
echo.
echo [OK] All tests passed successfully.
) else (
echo Status: FAILED
echo.
echo [ERROR] Test failures detected.
echo.
echo Failed test output (last 30 lines^):
echo -----------------------------------
powershell -NoProfile -Command "Get-Content '%logfile%' | Select-Object -Last 30"
)
echo.
echo Full log: %logfile%
echo =============================================
exit /b !test_result!
Pre-Commit Test Gate
Run tests before allowing a git commit:
@echo off
setlocal
echo [PRE-COMMIT] Running tests before commit...
echo.
:: Run the test suite
call npm test >nul 2>&1
set "result=%errorlevel%"
if %result%==0 (
echo [OK] Tests passed. Proceeding with commit.
exit /b 0
) else (
echo [BLOCKED] Tests failed! Fix failures before committing.
echo.
echo Run "npm test" to see details.
exit /b 1
)
To use this as an automatic Git hook on Windows, create a shell script at .git/hooks/pre-commit that delegates to the batch file:
#!/bin/sh
exec cmd.exe //C "$(dirname "$0")/pre-commit-tests.bat"
Git for Windows executes hooks through its bundled bash shell, which cannot interpret batch syntax directly. The shell wrapper above bridges the two. Alternatively, tools like Husky (for Node.js projects) handle cross-platform hook setup automatically.
Build Pipeline Integration
A complete build script that runs tests as part of the deployment pipeline:
@echo off
setlocal
echo =============================================
echo BUILD PIPELINE
echo =============================================
echo.
:: Stage 1: Build
echo [1/3] Building...
dotnet build -c Release > build.log 2>&1
if %errorlevel% neq 0 (
echo [FAIL] Build failed!
type build.log
exit /b 1
)
echo Build succeeded.
:: Stage 2: Test
echo [2/3] Running tests...
dotnet test --no-build -c Release --logger "trx" > test.log 2>&1
set "test_result=%errorlevel%"
if %test_result% neq 0 (
echo [FAIL] Tests failed!
type test.log
exit /b 1
)
echo All tests passed.
:: Stage 3: Package
echo [3/3] Creating package...
dotnet publish -c Release -o publish > publish.log 2>&1
if %errorlevel% neq 0 (
echo [FAIL] Publish failed!
type publish.log
exit /b 1
)
echo Package ready in: publish\
echo.
echo =============================================
echo PIPELINE COMPLETE - Ready to deploy
echo =============================================
Common Mistakes
The Wrong Way: Not Checking the Exit Code
:: WRONG - Ignores whether tests passed or failed
dotnet test MyApp.Tests
echo "Tests done, deploying..."
:: Deploys even if tests failed!
Output Concern:
Without checking %errorlevel%, the script continues even after test failures, potentially deploying broken code. Always check the exit code and halt the pipeline on failure.
The Wrong Way: Using npm Without CALL
:: WRONG - Script terminates after npm finishes
npm test
echo This line never executes
npm.cmd is a Batch file itself. Running it without call causes the current script to terminate when npm finishes. Always use call npm test.
Best Practices
- Always check
%errorlevel%: Gate subsequent actions (deploy, commit, package) on test success. - Log output to files: Capture test output for debugging and historical records.
- Generate structured reports: Use TRX (
.trx), JUnit XML, or similar formats for CI/CD integration. - Use
callfor .cmd/.bat tools: npm, Maven, and other tools wrapped in Batch files requirecall. - Show failure details: On failure, display the last few lines of output to help diagnose the issue without opening the full log.
Conclusion
Running unit tests and capturing results from a Batch Script is a straightforward pattern: execute the test command, capture the exit code with %errorlevel%, redirect output to a log file, and take action based on pass or fail. This pattern works identically across .NET, Python, Node.js, Java, and any other test framework that follows the standard exit code convention. By integrating test execution into build scripts, pre-commit hooks, and deployment pipelines, teams ensure that code quality gates are enforced automatically at every stage of the development workflow.