VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/UnitTestFrameworkPkg/ReadMe.md@ 101283

最後變更 在這個檔案從101283是 99404,由 vboxsync 提交於 2 年 前

Devices/EFI/FirmwareNew: Update to edk2-stable202302 and make it build, bugref:4643

  • 屬性 svn:eol-style 設為 native
檔案大小: 33.9 KB
 
1# Unit Test Framework Package
2
3## About
4
5This package provides unit test frameworks capable of building tests for multiple contexts including
6the UEFI shell environment and host-based environments. It allows for unit test development to focus
7on the tests and leave error logging, result formatting, context persistence, and test running to the framework.
8The unit test framework works well for low level unit tests as well as system level tests and
9fits easily in automation frameworks.
10
11### Framework
12
13The first unit test framework is called **Framework** and is implemented as a set of EDK II libraries.
14The Framework supports both host-based unit tests and target-based unit tests that share the same
15source style, macros, and APIs. In some scenarios, the same unit test case sources can be built
16for both host-based unit test execution and target-based unit test execution. Host-based unit tests
17that require mocked interfaces can use the mocking infrastructure provided by
18[cmocka](https://api.cmocka.org/) that is included in the UnitTestFrameworkPkg as a submodule.
19
20### GoogleTest
21
22The second unit test framework supported by the UnitTestFrameworkPkg is
23[GoogleTest](http://google.github.io/googletest/) that can be used to implement host-based unit tests.
24Use of GoogleTest for target-based unit tests of EDK II components is not supported. If a
25host-based unit test requires mocked interfaces, then the Framework with cmocka support should be
26used instead. Enabling support for mocked interfaces with GoogleTest is being actively investigated.
27[GoogleTest on GitHub](https://github.com/google/googletest) is included in the UnitTestFrameworkPkg
28as a submodule.
29
30GoogleTest requires less overhead to register test suites and test cases compared to the Framework.
31There are also a number of tools that layer on top of GoogleTest that improve developer productivity.
32One example is the VS Code extension
33[C++ TestMate](https://marketplace.visualstudio.com/items?itemName=matepek.vscode-catch2-test-adapter)
34that may be used to implement, run, and debug unit tests implemented using GoogleTest.
35
36If a component can be tested with host-based unit tests without support for mocked interfaces,
37then GoogleTest is recommended. The MdePkg contains a port of the BaseSafeIntLib unit tests in
38the GoogleTest style so the differences between GoogleTest and Framework unit tests can be reviewed.
39The paths to the BaseSafeIntLib unit tests are:
40
41* MdePkg\Test\UnitTest\Library\BaseSafeIntLib
42* MdePkg\Test\GoogleTest\Library\BaseSafeIntLib
43
44## Framework and GoogleTest Feature Comparison
45
46| Feature | Framework | GoogleTest |
47|:----------------------------|:---------:|:----------:|
48| Host Based Unit Tests | YES | YES |
49| Target Based Unit Tests | YES | NO |
50| Unit Test Source Language | C | C++ |
51| Register Test Suite | YES | Auto |
52| Register Test Case | YES | Auto |
53| Death/Expected Assert Tests | YES | YES |
54| Setup/Teardown Hooks | YES | YES |
55| Value-Parameterized Tests | NO | YES |
56| Typed Tests | NO | YES |
57| Type-Parameterized Tests | NO | YES |
58| Timeout Support | NO | YES |
59| Mocking Support | Cmocka | NO |
60| JUNIT XML Reports | YES | YES |
61| Execute subset of tests | NO | YES |
62| VS Code Extensions | NO | YES |
63
64## Framework Libraries
65
66### UnitTestLib
67
68The main "framework" library. The core of the framework is the Framework object, which can have any number
69of test cases and test suites registered with it. The Framework object is also what drives test execution.
70
71The Framework also provides helper macros and functions for checking test conditions and
72reporting errors. Status and error info will be logged into the test context. There are a number
73of Assert macros that make the unit test code friendly to view and easy to understand.
74
75Finally, the Framework also supports logging strings during the test execution. This data is logged
76to the test context and will be available in the test reporting phase. This should be used for
77logging test details and helpful messages to resolve test failures.
78
79### UnitTestPersistenceLib
80
81Persistence lib has the main job of saving and restoring test context to a storage medium so that for tests
82that require exiting the active process and then resuming state can be maintained. This is critical
83in supporting a system reboot in the middle of a test run.
84
85### UnitTestResultReportLib
86
87Library provides function to run at the end of a framework test run and handles formatting the report.
88This is a common customization point and allows the unit test framework to fit its output reports into
89other test infrastructure. In this package simple library instances have been supplied to output test
90results to the console as plain text.
91
92## Framework Samples
93
94There is a sample unit test provided as both an example of how to write a unit test and leverage
95many of the features of the framework. This sample can be found in the `Test/UnitTest/Sample/SampleUnitTest`
96directory.
97
98The sample is provided in PEI, SMM, DXE, and UEFI App flavors. It also has a flavor for the HOST_APPLICATION
99build type, which can be run on a host system without needing a target.
100
101## Framework Usage
102
103This section is built a lot like a "Getting Started". We'll go through some of the components that are needed
104when constructing a unit test and some of the decisions that are made by the test writer. We'll also describe
105how to check for expected conditions in test cases and a bit of the logging characteristics.
106
107Most of these examples will refer to the SampleUnitTestUefiShell app found in this package.
108
109### Framework Requirements - INF
110
111In our INF file, we'll need to bring in the `UnitTestLib` library. Conveniently, the interface
112header for the `UnitTestLib` is located in `MdePkg`, so you shouldn't need to depend on any other
113packages. As long as your DSC file knows where to find the lib implementation that you want to use,
114you should be good to go.
115
116See this example in 'SampleUnitTestUefiShell.inf'...
117
118```
119[Packages]
120 MdePkg/MdePkg.dec
121
122[LibraryClasses]
123 UefiApplicationEntryPoint
124 BaseLib
125 DebugLib
126 UnitTestLib
127 PrintLib
128```
129
130Also, if you want you test to automatically be picked up by the Test Runner plugin, you will need
131to make sure that the module `BASE_NAME` contains the word `Test`...
132
133```
134[Defines]
135 BASE_NAME = SampleUnitTestUefiShell
136```
137
138### Framework Requirements - Code
139
140Not to state the obvious, but let's make sure we have the following include before getting too far along...
141
142```c
143#include <Library/UnitTestLib.h>
144```
145
146Now that we've got that squared away, let's look at our 'Main()'' routine (or DriverEntryPoint() or whatever).
147
148### Framework Configuration
149
150Everything in the UnitTestFrameworkPkg framework is built around an object called -- conveniently -- the Framework.
151This Framework object will contain all the information about our test, the test suites and test cases associated
152with it, the current location within the test pass, and any results that have been recorded so far.
153
154To get started with a test, we must first create a Framework instance. The function for this is
155`InitUnitTestFramework`. It takes in `CHAR8` strings for the long name, short name, and test version.
156The long name and version strings are just for user presentation and relatively flexible. The short name
157will be used to name any cache files and/or test results, so should be a name that makes sense in that context.
158These strings are copied internally to the Framework, so using stack-allocated or literal strings is fine.
159
160In the 'SampleUnitTestUefiShell' app, the module name is used as the short name, so the initialization looks like this.
161
162```c
163DEBUG(( DEBUG_INFO, "%a v%a\n", UNIT_TEST_APP_NAME, UNIT_TEST_APP_VERSION ));
164
165//
166// Start setting up the test framework for running the tests.
167//
168Status = InitUnitTestFramework( &Framework, UNIT_TEST_APP_NAME, gEfiCallerBaseName, UNIT_TEST_APP_VERSION );
169```
170
171The `&Framework` returned here is the handle to the Framework. If it's successfully returned, we can start adding
172test suites and test cases.
173
174Test suites exist purely to help organize test cases and to differentiate the results in reports. If you're writing
175a small unit test, you can conceivably put all test cases into a single suite. However, if you end up with 20+ test
176cases, it may be beneficial to organize them according to purpose. You _must_ have at least one test suite, even if
177it's just a catch-all. The function to create a test suite is `CreateUnitTestSuite`. It takes in a handle to
178the Framework object, a `CHAR8` string for the suite title and package name, and optional function pointers for
179a setup function and a teardown function.
180
181The suite title is for user presentation. The package name is for xUnit type reporting and uses a '.'-separated
182hierarchical format (see 'SampleUnitTestApp' for example). If provided, the setup and teardown functions will be
183called once at the start of the suite (before _any_ tests have run) and once at the end of the suite (after _all_
184tests have run), respectively. If either or both of these are unneeded, pass `NULL`. The function prototypes are
185`UNIT_TEST_SUITE_SETUP` and `UNIT_TEST_SUITE_TEARDOWN`.
186
187Looking at 'SampleUnitTestUefiShell' app, you can see that the first test suite is created as below...
188
189```c
190//
191// Populate the SimpleMathTests Unit Test Suite.
192//
193Status = CreateUnitTestSuite( &SimpleMathTests, Fw, "Simple Math Tests", "Sample.Math", NULL, NULL );
194```
195
196This test suite has no setup or teardown functions. The `&SimpleMathTests` returned here is a handle to the suite and
197will be used when adding test cases.
198
199Great! Now we've finished some of the cruft, red tape, and busy work. We're ready to add some tests. Adding a test
200to a test suite is accomplished with the -- you guessed it -- `AddTestCase` function. It takes in the suite handle;
201a `CHAR8` string for the description and class name; a function pointer for the test case itself; additional, optional
202function pointers for prerequisite check and cleanup routines; and an optional pointer to a context structure.
203
204Okay, that's a lot. Let's take it one piece at a time. The description and class name strings are very similar in
205usage to the suite title and package name strings in the test suites. The former is for user presentation and the
206latter is for xUnit parsing. The test case function pointer is what is executed as the "test" and the
207prototype should be `UNIT_TEST_FUNCTION`. The last three parameters require a little bit more explaining.
208
209The prerequisite check function has a prototype of `UNIT_TEST_PREREQUISITE` and -- if provided -- will be called
210immediately before the test case. If this function returns any error, the test case will not be run and will be
211recorded as `UNIT_TEST_ERROR_PREREQUISITE_NOT_MET`. The cleanup function (prototype `UNIT_TEST_CLEANUP`) will be called
212immediately after the test case to provide an opportunity to reset any global state that may have been changed in the
213test case. In the event of a prerequisite failure, the cleanup function will also be skipped. If either of these
214functions is not needed, pass `NULL`.
215
216The context pointer is entirely case-specific. It will be passed to the test case upon execution. One of the purposes
217of the context pointer is to allow test case reuse with different input data. (Another use is for testing that wraps
218around a system reboot, but that's beyond the scope of this guide.) The test case must know how to interpret the context
219pointer, so it could be a simple value, or it could be a complex structure. If unneeded, pass `NULL`.
220
221In 'SampleUnitTestUefiShell' app, the first test case is added using the code below...
222
223```c
224AddTestCase( SimpleMathTests, "Adding 1 to 1 should produce 2", "Addition", OnePlusOneShouldEqualTwo, NULL, NULL, NULL );
225```
226
227This test case calls the function `OnePlusOneShouldEqualTwo` and has no prerequisite, cleanup, or context.
228
229Once all the suites and cases are added, it's time to run the Framework.
230
231```c
232//
233// Execute the tests.
234//
235Status = RunAllTestSuites( Framework );
236```
237
238### Framework - A Simple Test Case
239
240We'll take a look at the below test case from 'SampleUnitTestApp'...
241
242```c
243UNIT_TEST_STATUS
244EFIAPI
245OnePlusOneShouldEqualTwo (
246 IN UNIT_TEST_FRAMEWORK_HANDLE Framework,
247 IN UNIT_TEST_CONTEXT Context
248 )
249{
250 UINTN A, B, C;
251
252 A = 1;
253 B = 1;
254 C = A + B;
255
256 UT_ASSERT_EQUAL(C, 2);
257 return UNIT_TEST_PASSED;
258} // OnePlusOneShouldEqualTwo()
259```
260
261The prototype for this function matches the `UNIT_TEST_FUNCTION` prototype. It takes in a handle to the Framework
262itself and the context pointer. The context pointer could be cast and interpreted as anything within this test case,
263which is why it's important to configure contexts carefully. The test case returns a value of `UNIT_TEST_STATUS`, which
264will be recorded in the Framework and reported at the end of all suites.
265
266In this test case, the `UT_ASSERT_EQUAL` assertion is being used to establish that the business logic has functioned
267correctly. There are several assertion macros, and you are encouraged to use one that matches as closely to your
268intended test criterium as possible, because the logging is specific to the macro and more specific macros have more
269detailed logs. When in doubt, there are always `UT_ASSERT_TRUE` and `UT_ASSERT_FALSE`. Assertion macros that fail their
270test criterium will immediately return from the test case with `UNIT_TEST_ERROR_TEST_FAILED` and log an error string.
271_Note_ that this early return can have implications for memory leakage.
272
273At the end, if all test criteria pass, you should return `UNIT_TEST_PASSED`.
274
275### Framework - More Complex Cases
276
277To write more advanced tests, first look at all the Assertion and Logging macros provided in the framework.
278
279Beyond that, if you're writing host-based tests and want to take a dependency on the UnitTestFrameworkPkg, you can
280leverage the `cmocka.h` interface and write tests with all the features of the Cmocka framework.
281
282Documentation for Cmocka can be found here:
283https://api.cmocka.org/
284
285## GoogleTest Samples
286
287There is a sample unit test provided as both an example of how to write a unit test and leverage
288many of the GoogleTest features. This sample can be found in the `Test/GoogleTest/Sample/SampleGoogleTest`
289directory.
290
291The sample is provided for the HOST_APPLICATION build type, which can be run on a host system without
292needing a target.
293
294## GoogleTest Usage
295
296This section is built a lot like a "Getting Started". We'll go through some of the components that are needed
297when constructing a unit test and some of the decisions that are made by the test writer. We'll also describe
298how to check for expected conditions in test cases and a bit of the logging characteristics.
299
300Most of these examples will refer to the SampleGoogleTestHost app found in this package.
301
302### GoogleTest Requirements - INF
303
304In our INF file, we'll need to bring in the `GoogleTest` library. Conveniently, the interface
305header for the `GoogleTest` is in `UnitTestFrameworkPkg`, so you shouldn't need to depend on any other
306packages. As long as your DSC file knows where to find the lib implementation that you want to use,
307you should be good to go.
308
309See this example in 'SampleGoogleTestHost.inf'...
310
311```
312[Packages]
313 MdePkg/MdePkg.dec
314 UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
315
316[LibraryClasses]
317 GoogleTestLib
318 BaseLib
319 DebugLib
320```
321
322Also, if you want you test to automatically be picked up by the Test Runner plugin, you will need
323to make sure that the module `BASE_NAME` contains the word `Test`...
324
325```
326[Defines]
327 BASE_NAME = SampleGoogleTestHost
328```
329
330### GoogleTest Requirements - Code
331
332Not to state the obvious, but let's make sure we have the following include before getting too far along...
333
334```
335#include <gtest/gtest.h>
336extern "C" {
337 #include <Uefi.h>
338 #include <Library/BaseLib.h>
339 #include <Library/DebugLib.h>
340}
341```
342
343GoogleTest applications are implemented in C++. The first include brings in the
344GoogleTest definitions. Other EDK II related include files must be wrapped in
345`extern "C" {}` because they are C include files. Link failures will occur if
346this is not done.
347
348Now that we've got that squared away, let's look at our 'Main()'' routine (or DriverEntryPoint() or whatever).
349
350### GoogleTest Configuration
351
352Unlike the Framework, GoogleTest does not require test suites or test cases to
353be registered. Instead, the test cases declare the test suite name and test
354case name as part of their implementation. The only requirement for GoogleTest
355is to have a `main()` function that initialize the GoogleTest infrastructure and
356call the service `RUN_ALL_TESTS()` to run all the unit tests.
357
358```c
359int main(int argc, char* argv[]) {
360 testing::InitGoogleTest(&argc, argv);
361 return RUN_ALL_TESTS();
362}
363```
364
365### GoogleTest - A Simple Test Case
366
367We'll look at the below test case from 'SampleGoogleTestHost'...
368
369```c
370TEST(SimpleMathTests, OnePlusOneShouldEqualTwo) {
371 UINTN A;
372 UINTN B;
373 UINTN C;
374
375 A = 1;
376 B = 1;
377 C = A + B;
378
379 ASSERT_EQ (C, 2);
380}
381```
382
383This uses the simplest form of a GoogleTest unit test using `TEST()` that
384declares the test suite name and the unit test name within that test suite.
385The unit test performs actions and typically makes calls to the code under test
386and contains test assertions to verify that the code under test behaves as
387expected for the given inputs.
388
389In this test case, the `ASSERT_EQ` assertion is being used to establish that the business logic has functioned
390correctly. There are several assertion macros, and you are encouraged to use one that matches as closely to your
391intended test criterium as possible, because the logging is specific to the macro and more specific macros have more
392detailed logs. When in doubt, there are always `ASSERT_TRUE` and `ASSERT_FALSE`. Assertion macros that fail their
393test criterium will immediately return from the test case with a failed status and log an error string.
394_Note_ that this early return can have implications for memory leakage.
395
396There is no return status from a GooglTest unit test. If no assertions are
397triggered then the unit test has a passing status.
398
399### GoogleTest - More Complex Cases
400
401To write more advanced tests, take a look at the
402[GoogleTest User's Guide](http://google.github.io/googletest/).
403
404## Development
405
406### Iterating on a Single Test
407
408When using the EDK2 Pytools for CI testing, the host-based unit tests will be built and run on any build that includes
409the `NOOPT` build target.
410
411If you are trying to iterate on a single test, a convenient pattern is to build only that test module. For example,
412the following command will build only the SafeIntLib host-based test from the MdePkg...
413
414```bash
415stuart_ci_build -c .pytool/CISettings.py TOOL_CHAIN_TAG=VS2017 -p MdePkg -t NOOPT BUILDMODULE=MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLib.inf
416```
417
418### Hooking BaseLib
419
420Most unit test mocking can be performed by the functions provided in the UnitTestFrameworkPkg libraries, but since
421BaseLib is consumed by the Framework itself, it requires different techniques to substitute parts of the
422functionality.
423
424To solve some of this, the UnitTestFrameworkPkg consumes a special implementation of BaseLib for host-based tests.
425This implementation contains a [hook table](https://github.com/tianocore/edk2/blob/e188ecc8b4aed8fdd26b731d43883861f5e5e7b4/MdePkg/Test/UnitTest/Include/Library/UnitTestHostBaseLib.h#L507)
426that can be used to substitute test functionality for any of the BaseLib functions. By default, this implementation
427will use the underlying BaseLib implementation, so the unit test writer only has to supply minimal code to test a
428particular case.
429
430### Debugging the Framework Itself
431
432While most of the tests that are produced by the UnitTestFrameworkPkg are easy to step through in a debugger, the Framework
433itself consumes code (mostly Cmocka) that sets its own build flags. These flags cause parts of the Framework to not
434export symbols and captures exceptions, and as such are harder to debug. We have provided a Stuart parameter to force
435symbolic debugging to be enabled.
436
437You can run a build by adding the `BLD_*_UNIT_TESTING_DEBUG=TRUE` parameter to enable this build option.
438
439```bash
440stuart_ci_build -c .pytool/CISettings.py TOOL_CHAIN_TAG=VS2019 -p MdePkg -t NOOPT BLD_*_UNIT_TESTING_DEBUG=TRUE
441```
442
443## Building and Running Host-Based Tests
444
445The EDK2 CI infrastructure provides a convenient way to run all host-based tests -- in the the entire tree or just
446selected packages -- and aggregate all the reports, including highlighting any failures. This functionality is
447provided through the Stuart build system (published by EDK2-PyTools) and the `NOOPT` build target. The sections that
448follow use Framework examples. Unit tests based on GoogleTest are built and run the same way. The text output and
449JUNIT XML output format have small differences.
450
451### Building Locally
452
453First, to make sure you're working with the latest PyTools, run the following command:
454
455```bash
456# Would recommend running this in a Python venv, but that's out of scope for this doc.
457python -m pip install --upgrade -r ./pip-requirements.txt
458```
459
460After that, the following commands will set up the build and run the host-based tests.
461
462```bash
463# Setup repo for building
464# stuart_setup -c ./.pytool/CISettings.py TOOL_CHAIN_TAG=<GCC5, VS2019, etc.>
465stuart_setup -c ./.pytool/CISettings.py TOOL_CHAIN_TAG=VS2019
466
467# Update all binary dependencies
468# stuart_update -c ./.pytool/CISettings.py TOOL_CHAIN_TAG=<GCC5, VS2019, etc.>
469stuart_update -c ./.pytool/CISettings.py TOOL_CHAIN_TAG=VS2019
470
471# Build and run the tests
472# stuart_ci_build -c ./.pytool/CISettings.py TOOL_CHAIN_TAG=<GCC5, VS2019, etc.> -t NOOPT [-p <Package Name>]
473stuart_ci_build -c ./.pytool/CISettings.py TOOL_CHAIN_TAG=VS2019 -t NOOPT -p MdePkg
474```
475
476### Evaluating the Results
477
478In your immediate output, any build failures will be highlighted. You can see these below as "WARNING" and "ERROR" messages.
479
480```text
481(edk_env) PS C:\_uefi\edk2> stuart_ci_build -c .\.pytool\CISettings.py TOOL_CHAIN_TAG=VS2019 -t NOOPT -p MdePkg
482
483SECTION - Init SDE
484SECTION - Loading Plugins
485SECTION - Start Invocable Tool
486SECTION - Getting Environment
487SECTION - Loading plugins
488SECTION - Building MdePkg Package
489PROGRESS - --Running MdePkg: Host Unit Test Compiler Plugin NOOPT --
490WARNING - Allowing Override for key TARGET_ARCH
491PROGRESS - Start time: 2020-07-27 17:18:08.521672
492PROGRESS - Setting up the Environment
493PROGRESS - Running Pre Build
494PROGRESS - Running Build NOOPT
495PROGRESS - Running Post Build
496SECTION - Run Host based Unit Tests
497SUBSECTION - Testing for architecture: X64
498WARNING - TestBaseSafeIntLibHost.exe Test Failed
499WARNING - Test SafeInt8ToUint8 - UT_ASSERT_EQUAL(0x5b:5b, Result:5c)
500c:\_uefi\edk2\MdePkg\Test\UnitTest\Library\BaseSafeIntLib\TestBaseSafeIntLib.c:35: error: Failure!
501ERROR - Plugin Failed: Host-Based Unit Test Runner returned 1
502CRITICAL - Post Build failed
503PROGRESS - End time: 2020-07-27 17:18:19.792313 Total time Elapsed: 0:00:11
504ERROR - --->Test Failed: Host Unit Test Compiler Plugin NOOPT returned 1
505ERROR - Overall Build Status: Error
506PROGRESS - There were 1 failures out of 1 attempts
507SECTION - Summary
508ERROR - Error
509
510(edk_env) PS C:\_uefi\edk2>
511```
512
513If a test fails, you can run it manually to get more details...
514
515```text
516(edk_env) PS C:\_uefi\edk2> .\Build\MdePkg\HostTest\NOOPT_VS2019\X64\TestBaseSafeIntLibHost.exe
517
518Int Safe Lib Unit Test Application v0.1
519---------------------------------------------------------
520------------ RUNNING ALL TEST SUITES --------------
521---------------------------------------------------------
522---------------------------------------------------------
523RUNNING TEST SUITE: Int Safe Conversions Test Suite
524---------------------------------------------------------
525[==========] Running 71 test(s).
526[ RUN ] Test SafeInt8ToUint8
527[ ERROR ] --- UT_ASSERT_EQUAL(0x5b:5b, Result:5c)
528[ LINE ] --- c:\_uefi\edk2\MdePkg\Test\UnitTest\Library\BaseSafeIntLib\TestBaseSafeIntLib.c:35: error: Failure!
529[ FAILED ] Test SafeInt8ToUint8
530[ RUN ] Test SafeInt8ToUint16
531[ OK ] Test SafeInt8ToUint16
532[ RUN ] Test SafeInt8ToUint32
533[ OK ] Test SafeInt8ToUint32
534[ RUN ] Test SafeInt8ToUintn
535[ OK ] Test SafeInt8ToUintn
536...
537```
538
539You can also, if you are so inclined, read the output from the exact instance of the test that was run during
540`stuart_ci_build`. The output file can be found on a path that looks like:
541
542`Build/<Package>/HostTest/<Arch>/<TestName>.<TestSuiteName>.<Arch>.result.xml`
543
544A sample of this output looks like:
545
546```xml
547<!--
548 Excerpt taken from:
549 Build\MdePkg\HostTest\NOOPT_VS2019\X64\TestBaseSafeIntLibHost.exe.Int Safe Conversions Test Suite.X64.result.xml
550 -->
551<?xml version="1.0" encoding="UTF-8" ?>
552<testsuites>
553 <testsuite name="Int Safe Conversions Test Suite" time="0.000" tests="71" failures="1" errors="0" skipped="0" >
554 <testcase name="Test SafeInt8ToUint8" time="0.000" >
555 <failure><![CDATA[UT_ASSERT_EQUAL(0x5c:5c, Result:5b)
556c:\_uefi\MdePkg\Test\UnitTest\Library\BaseSafeIntLib\TestBaseSafeIntLib.c:35: error: Failure!]]></failure>
557 </testcase>
558 <testcase name="Test SafeInt8ToUint16" time="0.000" >
559 </testcase>
560 <testcase name="Test SafeInt8ToUint32" time="0.000" >
561 </testcase>
562 <testcase name="Test SafeInt8ToUintn" time="0.000" >
563 </testcase>
564```
565
566### XML Reporting Mode
567
568Unit test applications using Framework are built using Cmocka that requires the
569following environment variables to be set to generate structured XML output
570rather than text:
571
572```
573CMOCKA_MESSAGE_OUTPUT=xml
574CMOCKA_XML_FILE=<absolute or relative path to output file>
575```
576
577Unit test applications using GoogleTest require the following environment
578variable to be set to generate structured XML output rather than text:
579
580```
581GTEST_OUTPUT=xml:<absolute or relative path to output file>
582```
583
584This mode is used by the test running plugin to aggregate the results for CI test status reporting in the web view.
585
586### Code Coverage
587
588Host based Unit Tests will automatically enable coverage data.
589
590For Windows, This is primarily leverage for pipeline builds, but this can be leveraged locally using the
591OpenCppCoverage windows tool to parse coverage data to cobertura xml format.
592
593- Windows Prerequisite
594 ```bash
595 Download and install https://github.com/OpenCppCoverage/OpenCppCoverage/releases
596 python -m pip install --upgrade -r ./pip-requirements.txt
597 stuart_ci_build -c .pytool/CISettings.py -t NOOPT TOOL_CHAIN_TAG=VS2019 -p MdeModulePkg
598 Open Build/coverage.xml
599 ```
600
601 - How to see code coverage data on IDE Visual Studio
602 ```
603 Open Visual Studio VS2019 or above version
604 Click "Tools" -> "OpenCppCoverage Settings"
605 Fill your execute file into "Program to run:"
606 Click "Tools" -> "Run OpenCppCoverage"
607 ```
608
609
610For Linux, This is primarily leveraged for pipeline builds, but this can be leveraged locally using the
611lcov linux tool, and parsed using the lcov_cobertura python tool to parse it to cobertura xml format.
612
613- Linux Prerequisite
614 ```bash
615 sudo apt-get install -y lcov
616 python -m pip install --upgrade -r ./pip-requirements.txt
617 stuart_ci_build -c .pytool/CISettings.py -t NOOPT TOOL_CHAIN_TAG=GCC5 -p MdeModulePkg
618 Open Build/coverage.xml
619 ```
620 - How to see code coverage data on IDE Visual Studio Code
621 ```
622 Download plugin "Coverage Gutters"
623 Press Hot Key "Ctrl + Shift + P" and click option "Coverage Gutters: Display Coverage"
624 ```
625
626
627### Important Note
628
629This works on both Windows and Linux but is currently limited to x64 architectures. Working on getting others, but we
630also welcome contributions.
631
632## Framework Known Limitations
633
634### PEI, DXE, SMM
635
636While sample tests have been provided for these execution environments, only cursory build validation
637has been performed. Care has been taken while designing the frameworks to allow for execution during
638boot phases, but only UEFI Shell and host-based tests have been thoroughly evaluated. Full support for
639PEI, DXE, and SMM is forthcoming, but should be considered beta/staging for now.
640
641### Host-Based Support vs Other Tests
642
643The host-based test framework is powered internally by the Cmocka framework. As such, it has abilities
644that the target-based tests don't (yet). It would be awesome if this meant that it was a super set of
645the target-based tests, and it worked just like the target-based tests but with more features. Unfortunately,
646this is not the case. While care has been taken to keep them as close as possible, there are a few known
647inconsistencies that we're still ironing out. For example, the logging messages in the target-based tests
648are cached internally and associated with the running test case. They can be saved later as part of the
649reporting lib. This isn't currently possible with host-based. Only the assertion failures are logged.
650
651We will continue trying to make these as similar as possible.
652
653## Unit Test Location/Layout Rules
654
655Code/Test | Location
656--------- | --------
657Host-Based Unit Tests for a Library/Protocol/PPI/GUID Interface | If what's being tested is an interface (e.g. a library with a public header file, like DebugLib), the test should be scoped to the parent package.<br/>Example: `MdePkg/Test/UnitTest/[Library/Protocol/Ppi/Guid]/`<br/><br/>A real-world example of this is the BaseSafeIntLib test in MdePkg.<br/>`MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibHost.inf`
658Host-Based Unit Tests for a Library/Driver (PEI/DXE/SMM) implementation | If what's being tested is a specific implementation (e.g. BaseDebugLibSerialPort for DebugLib), the test should be scoped to the implementation directory itself, in a UnitTest subdirectory.<br/><br/>Module Example: `MdeModulePkg/Universal/EsrtFmpDxe/UnitTest/`<br/>Library Example: `MdePkg/Library/BaseMemoryLib/UnitTest/`
659Host-Based Tests for a Functionality or Feature | If you're writing a functional test that operates at the module level (i.e. if it's more than a single file or library), the test should be located in the package-level Tests directory under the HostFuncTest subdirectory.<br/>For example, if you were writing a test for the entire FMP Device Framework, you might put your test in:<br/>`FmpDevicePkg/Test/HostFuncTest/FmpDeviceFramework`<br/><br/>If the feature spans multiple packages, it's location should be determined by the package owners related to the feature.
660Non-Host-Based (PEI/DXE/SMM/Shell) Tests for a Functionality or Feature | Similar to Host-Based, if the feature is in one package, should be located in the `*Pkg/Test/[Shell/Dxe/Smm/Pei]Test` directory.<br/><br/>If the feature spans multiple packages, it's location should be determined by the package owners related to the feature.<br/><br/>USAGE EXAMPLES<br/>PEI Example: MP_SERVICE_PPI. Or check MTRR configuration in a notification function.<br/> SMM Example: a test in a protocol callback function. (It is different with the solution that SmmAgent+ShellApp)<br/>DXE Example: a test in a UEFI event call back to check SPI/SMRAM status. <br/> Shell Example: the SMM handler audit test has a shell-based app that interacts with an SMM handler to get information. The SMM paging audit test gathers information about both DXE and SMM. And the SMM paging functional test actually forces errors into SMM via a DXE driver.
661
662### Example Directory Tree
663
664```text
665<PackageName>Pkg/
666 ComponentY/
667 ComponentY.inf
668 ComponentY.c
669 GoogleTest/
670 ComponentYHostGoogleTest.inf # Host-Based Test for Driver Module
671 ComponentYGoogleTest.cpp
672 UnitTest/
673 ComponentYHostUnitTest.inf # Host-Based Test for Driver Module
674 ComponentYUnitTest.c
675
676 Library/
677 GeneralPurposeLibBase/
678 ...
679
680 GeneralPurposeLibSerial/
681 ...
682
683 SpecificLibDxe/
684 SpecificLibDxe.c
685 SpecificLibDxe.inf
686 GoogleTest/ # Host-Based Test for Specific Library Implementation
687 SpecificLibDxeHostGoogleTest.cpp
688 SpecificLibDxeHostGoogleTest.inf
689 UnitTest/ # Host-Based Test for Specific Library Implementation
690 SpecificLibDxeHostUnitTest.c
691 SpecificLibDxeHostUnitTest.inf
692 Test/
693 <Package>HostTest.dsc # Host-Based Test Apps
694 GoogleTest/
695 InterfaceX
696 InterfaceXHostGoogleTest.inf # Host-Based App (should be in Test/<Package>HostTest.dsc)
697 InterfaceXUnitTest.cpp # Test Logic
698
699 GeneralPurposeLib/ # Host-Based Test for any implementation of GeneralPurposeLib
700 GeneralPurposeLibTest.cpp
701 GeneralPurposeLibHostUnitTest.inf
702
703 UnitTest/
704 InterfaceX
705 InterfaceXHostUnitTest.inf # Host-Based App (should be in Test/<Package>HostTest.dsc)
706 InterfaceXPeiUnitTest.inf # PEIM Target-Based Test (if applicable)
707 InterfaceXDxeUnitTest.inf # DXE Target-Based Test (if applicable)
708 InterfaceXSmmUnitTest.inf # SMM Target-Based Test (if applicable)
709 InterfaceXShellUnitTest.inf # Shell App Target-Based Test (if applicable)
710 InterfaceXUnitTest.c # Test Logic
711
712 GeneralPurposeLib/ # Host-Based Test for any implementation of GeneralPurposeLib
713 GeneralPurposeLibTest.c
714 GeneralPurposeLibHostUnitTest.inf
715
716 <Package>Pkg.dsc # Standard Modules and any Target-Based Test Apps (including in Test/)
717
718```
719
720### Future Locations in Consideration
721
722We don't know if these types will exist or be applicable yet, but if you write a support library or module that matches the following, please make sure they live in the correct place.
723
724Code/Test | Location
725--------- | --------
726Host-Based Library Implementations | Host-Based Implementations of common libraries (eg. MemoryAllocationLibHost) should live in the same package that declares the library interface in its .DEC file in the `*Pkg/HostLibrary` directory. Should have 'Host' in the name.
727Host-Based Mocks and Stubs | Mock and Stub libraries should live in the `UefiTestFrameworkPkg/StubLibrary` with either 'Mock' or 'Stub' in the library name.
728
729### If still in doubt...
730
731Hop on GitHub and ask @corthon, @mdkinney, or @spbrogan. ;)
732
733## Copyright
734
735Copyright (c) Microsoft Corporation.
736SPDX-License-Identifier: BSD-2-Clause-Patent
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette