teemperor updated this revision to Diff 340520.
teemperor marked 5 inline comments as done.
teemperor added a comment.
- Update diff with feedback.
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D101153/new/
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,129 @@
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 and should be avoided if possible. A large part
+ of LLDB's functionality is available directly after creating an `SBTarget`
+ of the test executable.
+
+ The part of the SB API that can be tested with just a target includes
+ everything that just represents information about the executable and its
+ debug information (e.g., `SBTarget`, `SBModule`, `SBSymbolContext`,
+ `SBFunction`, `SBInstruction`, `SBCompileUnit`, etc.). For test executables
+ written in languages with a type system that is mostly defined at compile
+ time (e.g., C and C++) there is also usually no process necessary to test
+ the `SBType`-related parts of the API. With those languages it's also
+ possible to test `SBValue` by running expressions with
+ `SBTarget.EvaluateExpression` or the `expect_expr` testing utility.
+
+ Functionality that always requires a running process is everything that
+ tests the `SBProcess`, `SBThread`, and `SBFrame` classes. The same is true
+ for tests that exercise to breakpoints, watchpoints and sanitizers.
+ Languages such as Objective-C that have a dependency on a runtime
+ environment also always require a running process.
+
+**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.
+
+**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), try to avoid specifying custom compiler
+ flags if possible. Certain debug information formats such as ``gmodules``
+ use a cache that is shared between all API tests and that contains
+ precompiled system headers. If you add or remove a specific compiler flag
+ in your test (e.g., adding ``-DFOO`` to the ``Makefile`` or ``self.build``
+ arguments), then the test will not use the shared precompiled header cache
+ and expensively recompile all system headers from scratch. If you depend on
+ a specific compiler flag for the test, you can avoid this issue by either
+ removing all system header includes or decorating the test function with
+ ``@no_debug_info_test`` (which will avoid running all debug information
+ variants including ``gmodules``).
+
+**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 will unexpectedly pass if it's ran as the first expression in a test:
+
+::
+
+ self.expect("expr 2 + 2", substrs=["0"])
+
+When running the same command in LLDB the reason for the unexpected success
+is that '0' is found in the name of the implicitly created result variable:
+
+::
+
+ (lldb) expr 2 + 2
+ (int) $0 = 4
+ ^ The '0' substring is found here.
+
+A better way to write the test above would be using LLDB's testing function
+``expect_expr`` will only pass if the expression produces a value of 0:
+
+::
+
+ self.expect_expr("2 + 2", result_value="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)
+
Running The Tests
-----------------
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits