Unit testing is a method used to verify that individual parts of your code
function as intended. SheerPower simplifies this process by enabling you to
quickly write and execute unit tests, which helps you identify bugs early
and maintain high code quality.
Testing your code is crucial. With SheerPower's extremely fast compile and
link times (typically under a second), you can easily write new code and
test it incrementally, every few lines. SheerPower also allows you to
conveniently write unit tests alongside your main code, ensuring continuous
verification as you develop.
Quick and Easy Unit Testing
SheerPower simplifies unit testing with a single command and two
intuitive directives:
option test on
: Activates test mode.
%test <statement>
: Executes the specified code
statements only in test mode.
%test_ignore <statement>
: Skips the specified
code statements in test mode.
This allows you to seamlessly integrate tests into your main
codebase and focus on maintaining code quality.
SheerPower's testing features help developers write reliable and error-free code by allowing them to
define and run unit tests easily. By using %test and %test_ignore directives,
developers can mark specific
routines and lines of code for testing or ignoring during test runs.
Enabling test mode with option test on ensures that all marked
tests are executed, providing immediate feedback on the code's functionality. This systematic
testing approach helps catch bugs early, maintain code quality, and ensure new changes
do not break existing functionality.
option test on
%test print 'We are in test mode'
age = 15
%test age = 25
debug show age
Let's say there is an include file filled with testing code. You could
conditionally compile and run that testing code by:
option test on
tax_rate = 6.5/100
%test %include 'safe_unit_tests.spinc'
Here is what safe_unit_tests.spinc looks like. Notice the use of the
assert statement. You tell
assert what is
expected and it produces an
exception if the assert fails:
// safe_unit_tests.spinc
print 'Testing the tax_rate of '; tax_rate
assert tax_rate > 0 and tax_rate <= 1.00, 'Tax rate is out of bounds'
print 'Tax rate is fine'
For clarity in your code, you can explicitly turn off test mode by:
option test off
By default, test mode is turned off.
Your code can contain any number of
option test on or
option test
off statements. However, for easier code maintenance, just having one at
the top of your program is best. Your code can also contain any number of
%test and
%test_ignore directives.
In addition to these directives, you can add one or more
debug all statements to your code.
This statement assists with debugging
by writing handy debug information to a file. This helps with debugging with:
- Comprehensive Debugging: Provides detailed information on variable values, routine calls, and errors.
- Runtime Execution: Helps debug complex issues by activating in the middle of program execution.
- Efficient Issue Identification: Aids in quickly locating and resolving bugs.
- Enhanced Debugging Insights: Offers thorough insights into program behavior,
facilitating deeper understanding and troubleshooting.
The debug information includes:
- the names of all variables and their current values
- the current call stack
- the names all open files and tables
- and more.
The name of the debug information file is in the form
myprogram_debug.txt where
myprogram is the name of your program.
This debug file is automatically generated whenever an unhandled exception (error) occurs,
making it easier for developers to track down issues,
as it includes variable values, call stacks, and open file information.
Optionally you can supply your own filename:
For example:
debug all "myfile.txt"
Using
debug all is especially helpful when dealing with
elusive bugs.
Common Errors Reported at compile-time:
- Uninitialized Variables
- Type Mismatches
- Missing Routine Parameters
- Misspelled variable names or routines names (suggested spellings are given)
- Syntax Errors with highlighting
- Inconsistent variable Scoping
Testing Features and Priorities
-
Automated Regression Testing
Priority: Critical
Why: Ensures that existing functionality remains
stable as changes are made.
How to Implement:
-
Identify and automate tests for the most critical and frequently
used parts of the system.
-
Use the
%test
and %test_ignore
directives to tag tests for critical routines or
modules.
-
Automate test execution using SheerPower’s fast compile-and-run
times.
-
Integration Testing
Priority: High
Why: Verifies that different parts of the system
work together as expected, critical for large systems with
interdependent modules.
How to Implement:
-
Focus on key interfaces and interactions between modules.
-
Use SheerPower's
debug all
or other tools to trace and log
interactions during tests.
-
Error Handling and Boundary Condition Tests
Priority: High
Why: Many bugs arise from untested error conditions
or edge cases.
How to Implement:
-
Identify error-prone areas (e.g., file I/O, networking, and user
input handling).
-
Use
assert
statements to enforce expectations in error handling
paths.
- Add
%test
cases specifically targeting error conditions.
-
Critical Path and High-Risk Code Coverage
Priority: High
Why: Focuses effort on code that is most critical to
system functionality or most likely to fail.
How to Implement:
- Use profiling tools to identify code paths executed most often.
-
Write unit tests for these areas first using
option test on
and
%test
and %test_ignore
.
- Gradually expand to less critical paths.
-
Unit Testing for Stable Modules
Priority: Medium-High
Why: Allows reliable testing of isolated components
without introducing flakiness.
How to Implement:
-
Target the most self-contained and well-documented modules first.
- Create unit tests with
%test
to validate individual routine behavior.
-
Test Framework for Future Development
Priority: High
Why: Ensures that all new code includes tests,
preventing regression issues from growing.
How to Implement:
- Establish policies requiring new code to include
%test
cases.
-
Integrate testing into development workflows with SheerPower’s
option test on
.
-
Debugging Integration
Priority: Medium
Why: Provides insights during test failures, speeding
up diagnosis and resolution.
How to Implement:
- Use
debug all
statements for enhanced logs during test runs.
-
Enable debug information for critical sections of code to track
variable states and call stacks.
-
Modular Test Organization
Priority: Medium
Why: Makes the testing effort scalable and manageable
across teams.
How to Implement:
-
Organize tests by modules, using separate files (e.g.,
module_name_tests.spinc).
- Use
%include
directives to include relevant test cases during test runs.
Summary:
SheerPower provides a powerful yet simplified approach to unit testing and
debugging, empowering developers to maintain high code quality with minimal
overhead. By integrating fast compile-and-run times, intuitive directives
like %test and %test_ignore, and comprehensive
debugging tools such as debug all, SheerPower ensures a seamless
and efficient development experience.
Key takeaways from this tutorial include:
-
Ease of Use: With directives like
option test on
, developers can enable test mode and execute
unit tests effortlessly, identifying bugs early in the development process.
-
Flexibility: Tests can be written alongside main code or
organized modularly, allowing for scalable and manageable testing frameworks.
-
Comprehensive Debugging: Tools like
debug all
provide detailed insights into program behavior,
facilitating the quick identification and resolution of elusive issues.
-
Incremental Development: SheerPower's near-instant compile
times encourage frequent testing, fostering a development process where code
is continuously verified as it evolves.
-
Error Prevention: Common compile-time errors, including
uninitialized variables and syntax issues, are flagged with helpful
suggestions, ensuring robust code from the start.
By adopting SheerPower's testing and debugging features, developers can
ensure the reliability of their applications and streamline their
workflows. Whether you're tackling critical regression testing or debugging
complex interactions, SheerPower equips you with the tools to succeed.
%todo Directive: Managing Future Improvements
The %todo
directive provides a formal way to flag parts
of your code that need future attention. It improves productivity by
making tasks easy to track without disrupting the flow of development.
At compile-time, %todo
produces a soft-error that
does not stop compilation but lists the issue, making it clickable in
the development environment for fast navigation.
Syntax
%todo developer_name description_text
-
developer_name (required): A name or initials of who is
responsible.
-
description_text (required): Brief description of the task or
reminder.
Example
%todo SSue Improve performance of this loop since it is a "hot spot"
Elements of Good %todo
Text
Writing useful %todo
entries makes your notes actionable and
easy to revisit. A good entry should contain:
- Clear intent: State exactly what needs to be done or reviewed.
- Specific context: Mention what part of the code or behavior is affected.
- Actionable phrasing: Use verbs like “fix,” “refactor,” “remove,” “investigate,” or “optimize.”
- Avoid vagueness: Don’t write "fix this"—say what needs fixing.
- Be concise: One line is ideal, especially for the hover preview in editors.
Good Examples
%todo JD Refactor this loop to reduce memory usage
%todo AL Investigate why login fails on invalid tokens
%todo MP Optimize sort algorithm for large datasets
Weak Examples
%todo JD Fix
%todo AL ???
%todo MP Look at this
Behavior
- Compilation will continue normally.
-
A soft warning message will be generated, showing the developer name Ssue
and the text.
-
In the SPDEV and or VSC editors, the %todo warning will be
clickable, allowing fast jumping to the relevant line of code.
Benefits
- Provides a formal, visible way to track pending work.
- Helps with project organization during active development.
- Avoids forgetting important tasks in large codebases.