[Lldb-commits] [PATCH] D101153: [lldb][NFC] Specify guidelines for API tests

Raphael Isemann via Phabricator via lldb-commits lldb-commits at lists.llvm.org
Fri Apr 23 04:10:44 PDT 2021


teemperor created this revision.
teemperor added a reviewer: LLDB.
teemperor added a project: LLDB.
Herald added a subscriber: JDevlieghere.
teemperor requested review of this revision.

This patch specifies a few guidelines that our API tests should follow.

The motivations for this are twofold:

1. API tests have unexpected pitfalls that especially new contributors run into when writing tests. To prevent the frustration of letting people figure those pitfalls out by trial-and-error, let's just document them briefly in one place.

2. It prevents some arguing about what is the right way to write tests. I really like to have fast and reliable API test suite, but I also don't want to be the bogeyman that has to insist in every review that the test should be rewritten to not launch a process for no good reason. It's much easier to just point to a policy document.

I omitted some guidelines that I think could be controversial (e.g., the whole "should assert message describe failure or success").


https://reviews.llvm.org/D101153

Files:
  lldb/docs/resources/test.rst


Index: lldb/docs/resources/test.rst
===================================================================
--- lldb/docs/resources/test.rst
+++ lldb/docs/resources/test.rst
@@ -196,6 +196,88 @@
 variants mean that more general tests should be API tests, so that they can be
 run against the different variants.
 
+Guidelines for API tests
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+API tests are expected to be fast, reliable and maintainable. To achieve this
+goal, API tests should conform to the following guidelines in addition to normal
+good testing practices.
+
+**Don't unnecessarily launch the test executable.**
+    Launching a process and running to a breakpoint can often be the most
+    expensive part of a test. While it's often required to have a running
+    process to test a certain feature, sometimes its possible to test a feature
+    with a (non-running) target.
+
+**Don't unnecessarily include system headers in test sources.**
+    Including external headers slows down the compilation of the test executable
+    and it makes reproducing test failures on other operating systems or
+    configurations harder. There is usually
+
+**Avoid specifying test-specific compiler flags when including system headers.**
+    If a test requires including a system header (e.g., a test for a libc++
+    formatter includes a libc++ header), always avoid specifying custom compiler
+    flags in the test's ``Makefile``. Certain debug information formats such as
+    ``gmodules`` need to recompile external headers when they encounter
+    test-specific flags (including defines) which can be very expensive.
+
+**Test programs should be kept simple.**
+    Test executables should do the minimum amount of work to bring the process
+    into the state that is required for the test. Simulating a 'real' program
+    that actually tries to do some useful task rarely helps with catching bugs
+    and makes the test much harder to debug and maintain. The test programs
+    should always be deterministic (i.e., do not generate and check against
+    random test values).
+
+**Identifiers in tests should be simple and descriptive.**
+    Often test program need to declare functions and classes which require
+    choosing some form of identifier for them. These identifiers should always
+    either be kept simple for small tests (e.g., ``A``, ``B``, ...) or have some
+    descriptive name (e.g., ``ClassWithTailPadding``, ``inlined_func``, ...).
+    Never choose identifiers that are already used anywhere else in LLVM or
+    other programs (e.g., don't name a class  ``VirtualFileSystem``, a function
+    ``llvm_unreachable``, or a namespace ``rapidxml``) as this will just mislead
+    people ``grep``'ing the LLVM repository for those strings.
+
+**Prefer LLDB testing utilities over directly working with the SB API.**
+    The ``lldbutil`` module and the ``TestBase`` class come with a large amount
+    of utility functions that can do common test setup tasks (e.g., starting a
+    test executable and running the process to a breakpoint). Using these
+    functions not only keeps the test shorter and free of duplicated code, but
+    they also follow best test suite practices and usually give much clearer
+    error messages if something goes wrong. The test utilities also contain
+    custom asserts and checks that should be preferably used (e.g.
+    ``self.assertSuccess``).
+
+**Prefer calling the SB API over checking command output.**
+    Avoid writing your tests on top of ``self.expect(...)`` calls that check
+    the output of LLDB commands and instead try calling into the SB API. Relying
+    on LLDB commands makes changing (and improving) the output/syntax of
+    commands harder and the resulting tests are often prone to accepting
+    incorrect test results. Especially improved error messages that contain
+    more information might cause these ``self.expect`` calls to unintentionally
+    find the required ``substrs``. For example, the following ``self.expect``
+    check always passes as long as it's the first expression in a test:
+
+::
+    self.expect("expr 1 - 1", substrs=["0"])
+
+**Prefer using specific asserts over the generic assertTrue/assertFalse.**.
+    The `self.assertTrue`/`self.assertFalse` functions should always be your
+    last option as they give non-descriptive error messages. The test class has
+    several expressive asserts such as `self.assertIn` that automatically
+    generate an explanation how the received values differ from the expected
+    ones. See the documentation of Python's `unittest` module to see what
+    asserts are available. If you can't find a specific assert that fits your
+    needs and you fall back to a generic assert, make sure you put useful
+    information into the assert's `msg` argument that help explain the failure.
+
+::
+    # Bad. Will print a generic error such as 'False is not True'.
+    self.assertTrue(expected_string in list_of_results)
+    # Good. Will print expected_string and the contents of list_of_results.
+    self.assertIn(expected_string, list_of_results) # Good.
+
 Running The Tests
 -----------------
 


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D101153.339972.patch
Type: text/x-patch
Size: 5153 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/lldb-commits/attachments/20210423/1ee7da00/attachment-0001.bin>


More information about the lldb-commits mailing list