In this Engineering Notebook post, I'll summarize the new unit testing 
framework. The new code is in the ekr-unit-test branch.

I'll discuss only the most interesting features, and will be as brief as 
possible. See PR #2159 <https://github.com/leo-editor/leo-editor/pull/2159> 
for the code-level details.

*tl;dr:* See the summary.

*@test and @suite were design and coding blunders*

- unitTest.leo had to be running to run Leo's unit tests.
- Each unit test required teardown code to ensure that it didn't change 
unitTest.leo.
- Using outline nodes as unittest data was faux clever. Plain text data is 
easier to understand.
- Leo's TestManager class, in leoTest.py, was a feeble imitation of 
python's unittest module.


*Leo's new unittests in leo/unittest are separate from Leo itself*

- The files in leo/unittests are completely separate from the code each 
file tests.
- The unittest and pytest modules "just work" on these test files.
- g.unitTesting is *never* true while Leo is running!
  This invariant has simplifying effects throughout Leo's code.

*Example: support for TravisCI*

The heart of the new version of run_travis_unit_tests.py is:

base_dir = os.path.dirname(__file__)
unittests_dir = os.path.abspath(os.path.join(
    base_dir, 'leo', 'unittests'))
suite = unittest.TestLoader().discover(unittests_dir)
runner = unittest.TextTestRunner(failfast=True, verbosity=1)
result = runner.run(suite)

Do you see? The code above does not use g, or any other part of Leo. The 
old version loaded Leo itself (by starting Leo's bridge), then ran tests 
using Leo's TestManager class.

*Code-level details*

Subclasses of the LeoUnitTest class (defined in leoTest2.py) contain all 
unit tests.

The *setUpClass *classmethod calls the (simple!!) *create_app* function 
(also defined in leoTest2.py) to create an instance of the LeoApp class. 
This instance uses a null gui and assigns a g.NullObject to g.app.db and 
other objects, ensuring that the LeoApp instance will be safe.

The *setUp *method creates a new, minimal, *test outline* for each separate 
unit test. Unit tests can *easily* alter this test outline!

Unit tests can do (almost) anything they like because (in effect) the 
LeoUnitTest class *throws away* each test outline at the end of each test! 
Unit tests are completely independent of each other!

Each unit test is responsible for setting any needed user setting.

*New commands support unit and coverage testing*

The new test-* commands run python's unittest module on selected parts of 
Leo's code. The test-all command discovers and runs all unit tests in 
leo/unittests.

The new cover-* commands run coverage tests on the given parts of Leo's 
code. There is no cover-all command.

Running test-all before pushing commits has become second nature. test-all 
is much faster than starting unitTest.leo!

*Summary*

Leo never runs during unit tests. g.unitTesting is always False while Leo 
runs.

The new unit tests never have to worry about damaging Leo! Unit tests can 
never interfere with each other.

Unit testing code *for* Leo is separate from Leo itself.

Python's unittest and pytest modules now work as intended. For the first 
time, it is possible to run coverage tests on Leo.

Leo's new test-* and cover-* commands run unit tests or coverage tests on 
Leo's code.

The ekr-unit-test branch eliminates unitTest.leo and replaces leoTest.py 
with leoTest2.py. 

leoTest2.py contains *only *the LeoUnitTest class and the create_app 
function.

I'll wait until Leo 6.4 goes out the door to merge the ekr-unit-test branch 
into devel. In the meantime, I'll do all new unit testing in ekr-unit-test. 
It would be unbearable to use the old unit testing framework!
Edward

-- 
You received this message because you are subscribed to the Google Groups 
"leo-editor" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/leo-editor/fac9703f-86e4-4bc8-a831-7d8e4ef42447n%40googlegroups.com.

Reply via email to