If your model includes instances of blocks from a library, you can test both the source block in the library, and individual block instances in other models. You can also test software-in-the-loop (SIL) code generated for a reusable library subsystem. First, create test harnesses for a library block to test your design. Once the library block meets your requirements, create test harnesses for linked blocks and test the subsystem instances. You can move test harnesses from the library to an instance and an instance to the library.
This procedure outlines an example workflow for testing library subsystems and linked subsystems.
Create a test case and a test harness for the library subsystem.
Test the library subsystem. If it fails your requirements, revise the design and test again.
Lock the library when your tests pass.
In your model, create a linked subsystem and retain the library test harnesses.
Compare the output of the linked instance to that of the library block using an equivalence test case.
Create additional test cases and test harnesses for the linked instance.
Promote a test harness from the linked subsystem to the library if you want to include the test harness with future linked subsystems.
A test harness for a library subsystem has specific properties:
Libraries do not compile, so a test harness for a library subsystem does not use compiled attributes such as data type or sample rate.
A test harness for a library subsystem does not generate conversion subsystems for the block inputs and outputs.
A library subsystem test harness does not use push or rebuild operations, because libraries do not use configuration parameters.
When you create a linked subsystem from a library subsystem, test harnesses copy to the linked instance. If you do not need the test harnesses, you can delete them. For instructions on deleting all test harnesses from a model, see Manage Test Harnesses.
When you create a test harness for a linked subsystem, the harness associates with the
linked subsystem, not the library subsystem. You can move a test harness from a linked
subsystem to the library subsystem. For example, this linked subsystem
Controller has three test harnesses. To move the
Requirements_Tests1 test harness to the library:
Click the harness badge on the linked subsystem.
Click the Harness Operations icon.
Select Move to Library.
A dialog box informs you that moving the harness removes it from the linked subsystem.
After confirmation, the harness appears with the library subsystem.
You can apply an iterative design and test workflow to libraries by testing a library block in a test harness and updating the component under test. Changes to the component under test synchronize to the library when you close the test harness.
If you have a library block whose design is complete, set your test harnesses to prevent changes to the component under test. You can set this property when you create the test harness or after harness creation. See Create Test Harnesses and Select Properties.
Verify a reusable subsystem in a library and in a larger system.
This example demonstrates a test case that confirms a library block meets a short set of requirements. After testing the library block, you execute a baseline test of a linked block and capture the baseline results. You then promote the baseline test harness to the library.
The library block controls a simple heat pump system by supplying on/off signals to a fan and compressor, and specifying the heat pump mode (heating or cooling).
Open the Test File
Enter the following to store paths and filenames for the example, and to open the test file. The test file contains a test case for the library block and for the block instance in a closed-loop model.
testFile = 'sltestHeatpumpLibraryTests.mldatx'; library = 'sltestHeatpumpLibraryExample'; system = 'sltestHeatpumpLibraryLinkExample'; open(testFile);
Expand the Library Block Test test suite, and highlight the Requirements Scenarios test case in the test browser. Expand the Test Harness section of System Under Test, and click the arrow to open the test harness for the library block.
open_system(library); sltest.harness.open([library '/Controller'],'Requirements_Tests');
The Test Sequence block sets three scenarios for the controller:
The controller at idle
The controller activating the fan only
The controller activating the heating and cooling system
The Test Assessment block in the test harness checks the signals for each scenario. Since the test inputs and assessments are contained in the test harness, and no baseline data is being captured, the test case is a simulation test.
Run the Requirements-Based Test
In the test manager, run the Requirements Scenarios test case. The
verify statement results show that the
control_out signals pass.
Open the Linked Block Model
In the test manager, expand Instance Test. Highlight the Baseline Test test case. In the System Under Test, click the arrow next to the Model field to open the model.
sltest.harness.close([library '/Controller'], 'Requirements_Tests'); open_system(system); sim(system);
The controller is a linked block to the library. It is associated with a test harness Baseline Test that compares simulation results of the instance against baseline data. In your workflow, successful baseline testing for an instances of a library block can show that the linked block simulates correctly in the containing model. The test harness supplies a sine wave temperature and captures the controller output.
Run the Baseline Test and Observe Results
In the test manager, click Run to execute the test. The results show that the baseline test passes.
Move the Test Harness to the Library
If you develop a particularly useful test for a linked block, you can promote the test harness from a linked block to the source library block. The test harness then copies to all future instances of the library block.
Move the Baseline_controller_tests test harness to the library block:
1. In the sltestHeatpumpLibraryLinkExample model, click the harness badge and hover over the Baseline_controller_tests test harness.
2. Click the harness operations icon
3. Select Move to Library. A dialog informs you that the operation deletes the test harness from the instance and adds it to the library. Click Yes.
4. The test harness moves to the Controller library block.
close_system(library,0); close_system(system,0); clear(library,system,testFile); sltest.testmanager.clear; sltest.testmanager.clearResults;
This example shows how to unit test a reusable component in a library. It tests software-in-the-loop (SIL) code generated for a subsystem by using an equivalence test.
The reusable library subsystem must be at the top level of the library and must have function interfaces to lock down the subsystem interface. For information on reusable subsystem libraries, function interfaces, and workflow limitations, see Library-Based Code Generation for Reusable Library Subsystems (Embedded Coder).
Set Up the Code Generation Environment
orig = Simulink.fileGenControl('get','CodeGenFolderStructure'); Simulink.fileGenControl('set','CodeGenFolderStructure',... Simulink.filegen.CodeGenFolderStructure.TargetEnvironmentSubfolder);
Open the Reusable Library
This library contains a subsystem block at the top level.
Build the Library
Build the reusable library to generate code and create the function interfaces. After the code generation completes, you can view the function interfaces by clicking the lower right corner the library to open the Manage Function Interfaces dialog box.
### Starting build procedure for: Double ### Generating code and artifacts to 'Target environment subfolder' folder structure ### Generating code into build folder: /tmp/Bdoc21a_1622859_234737/tp5cc1526b/ex98874249/IntelWin64/Double ### Invoking Target Language Compiler on Double.rtw ### Using System Target File: /mathworks/devel/bat/Bdoc21a/build/matlab/rtw/c/ert/ert.tlc ### Loading TLC function libraries ...... ### Initial pass through model to cache user defined code . ### Caching model source code ............................................ ### Writing header file Subsystem_8qFtgSZM.c . ### Writing header file Double_types.h ### Writing header file Double.h ### Writing header file rtwtypes.h ### Writing header file Subsystem_8qFtgSZM.h ### Writing source file Double.c . ### Writing header file Double_private.h ### Writing source file ert_main.c ### TLC code generation complete. ### Using toolchain: GNU gcc/g++ | gmake (64-bit Linux) ### Creating '/tmp/Bdoc21a_1622859_234737/tp5cc1526b/ex98874249/IntelWin64/_shared/rtwshared.mk' ... ### Using toolchain: GNU gcc/g++ | gmake (64-bit Linux) ### Creating '/tmp/Bdoc21a_1622859_234737/tp5cc1526b/ex98874249/IntelWin64/Double/Double.mk' ... ### Successful completion of code generation for: Double The following files will be copied from IntelWin64/_shared to /tmp/Bdoc21a_1622859_234737/tp5cc1526b/ex98874249/IntelWin64/ReuseLibSubsysExample/R2021a: Subsystem_8qFtgSZM.c Subsystem_8qFtgSZM.h shared_file.dmr Files copied from IntelWin64/_shared to /tmp/Bdoc21a_1622859_234737/tp5cc1526b/ex98874249/IntelWin64/ReuseLibSubsysExample/R2021a. ### Starting build procedure for: Single ### Generating code and artifacts to 'Target environment subfolder' folder structure ### Generating code into build folder: /tmp/Bdoc21a_1622859_234737/tp5cc1526b/ex98874249/IntelWin64/Single ### Invoking Target Language Compiler on Single.rtw ### Using System Target File: /mathworks/devel/bat/Bdoc21a/build/matlab/rtw/c/ert/ert.tlc ### Loading TLC function libraries ...... ### Initial pass through model to cache user defined code . ### Caching model source code ............................................ ### Writing header file Subsystem_JUQsZMO7.c ### Writing header file Single_types.h . ### Writing header file Single.h ### Writing header file Subsystem_JUQsZMO7.h ### Writing source file Single.c ### Writing header file Single_private.h ### Writing source file ert_main.c . ### TLC code generation complete. ### Using toolchain: GNU gcc/g++ | gmake (64-bit Linux) ### Creating '/tmp/Bdoc21a_1622859_234737/tp5cc1526b/ex98874249/IntelWin64/_shared/rtwshared.mk' ... ### Using toolchain: GNU gcc/g++ | gmake (64-bit Linux) ### Creating '/tmp/Bdoc21a_1622859_234737/tp5cc1526b/ex98874249/IntelWin64/Single/Single.mk' ... ### Successful completion of code generation for: Single The following files will be copied from IntelWin64/_shared to /tmp/Bdoc21a_1622859_234737/tp5cc1526b/ex98874249/IntelWin64/ReuseLibSubsysExample/R2021a: Subsystem_JUQsZMO7.c Subsystem_JUQsZMO7.h shared_file.dmr Files copied from IntelWin64/_shared to /tmp/Bdoc21a_1622859_234737/tp5cc1526b/ex98874249/IntelWin64/ReuseLibSubsysExample/R2021a.
Select the Subsystem Component and Open the Test Manager
Click on the Subsystem in the library model to select it. Then, open the Test Manager.
Open the Test File
In the Test Manager, click Open and select the
Enable Coverage Collection
Select ReuseLibSubsysTest in the Test Browser pane.
Then, expand the Coverage Settings section in the main pane.
In Coverage to Collect, check Record coverage for system under test.
In Coverage Metrics, check that Decision, MCDC, and Condition are selected.
Open the Create Test for Model Component wizard
Click the arrow under New and select Test for Model Component to open the Create Test for Model Component wizard.
On the first page of the wizard, click the Use currently selected model component icon next to the Component field. Both the Component and Top Model fields fill in.
Click the refresh icon next to the Select function interface field and select Double from the dropdown.
Select the Test Inputs
Select Use Design Verifier to generate test input scenarios.
Select Inports as the test harness input source.
Select How to Test the Component
Select Perform back-to-back testing.
Set Simulation1 to Normal mode.
Set Simulation2 to Software-in-the-Loop (SIL) mode.
Specify the Data File Format and Location
Select MAT as the file format.
Select Add tests to currently selected test file.
Generate the Test Case and Return to the Test Manager
Click Done to generate the Double_harness1 test case for the Double function interface.
After test case generation completes, the Double_harness1 test case appears in the Test Manager. Notice that the Simulation Mode for Simulation1 is set to Normal and Simulation2 is set to Software-in-the-Loop (SIL) mode.
Run the Test
View Equivalence Results
Expand the Results to view the Equivalence Criteria Result. Notice that the Differences plot shows no differences between the two signals, which indicates that the Normal and SIL simulations are producing the same results. The SIL code associated with the reusable library subsystem can be reused for other SIL tests.
View Coverage Results
Expand the Aggregated Coverage section to view the coverage results. The two coverage results that show 100% are for the equivalence test run for the Double function interface. The other two results show 0% or no coverage because the Single function interface was not tested.