This is one of the main features of DynamicMacros. By using three empty lines, or a custom delimeter (highly recommended), you can split the macro and receive variable updates. Note that this doesn’t work inside if statements or for loops.
DynamicMacro version of your macro:
[gcode_macro run_increment_test_number]
gcode:
RESPOND TYPE=command MSG="Current Test Number {printer["gcode_macro test_number"].testnumber}"
increment_test_number
RESPOND TYPE=command MSG="Test Number after increment {printer["gcode_macro test_number"].testnumber}"