{"id":1938,"date":"2018-11-13T13:09:11","date_gmt":"2018-11-13T18:09:11","guid":{"rendered":"https:\/\/blogs.mathworks.com\/developer\/?p=1938"},"modified":"2018-11-13T13:09:59","modified_gmt":"2018-11-13T18:09:59","slug":"simulink-test-html-report","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/developer\/2018\/11\/13\/simulink-test-html-report\/","title":{"rendered":"Reporting for Duty"},"content":{"rendered":"<div class=\"content\"><p>Hello all! I was reading up on Guy's blog the other day and remembered his great post showing a <a href=\"https:\/\/blogs.mathworks.com\/simulink\/2018\/09\/04\/continuous-integration-with-simulink-project-and-simulink-test\/\">Simulink Test workflow with Jenkins and GitLab<\/a>. One thing I thought was cool in his musings was how he set it up to store the results so that you didn't need to rerun the tests to begin investigating.<\/p><p>Well I am happy to report that may be even easier in R2018b in your CI workflows since the <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/matlab.unittest.plugins.testreportplugin-class.html\">TestReportPlugin<\/a> now includes all the Simulink Test specific information in the report. This means that you can even begin to debug the problem or get an idea of why the tests failed from directly in your browser by looking at your CI dashboard. This then allows you to perhaps identify the right person to further debug and fix the problem much more efficiently. Just doin our part to keep your workflows well-oiled!<\/p><p>This is really easy to do. To see it in action let's just look at one of the Simulink Test examples, the f14ParameterSweepTest. This test has a few failures that we can hopefully glean some quick insight into. To run this as part of your CI build, you'll need to make a few quick connections. First, for example, you'll want to ensure your Simulink Test file(s) are configured to generate a report. Really all you'll need to do is open the file in Test Manager and click the option to generate the report:<\/p><pre class=\"codeinput\">testFile = <span class=\"string\">'f14ParameterSweepTest.mldatx'<\/span>;\r\nsltest.testmanager.view;\r\nsltest.testmanager.load(testFile);\r\n<\/pre><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"http:\/\/blogs.mathworks.com\/developer\/files\/y2018SLTestReportUnchecked.png\" alt=\"\"> <\/p><p>Once this is checked you'll see some more options. You should just be able to use the default selections to see the value here, but if you want you can tweak what is included in the report.<\/p><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"http:\/\/blogs.mathworks.com\/developer\/files\/y2018SLTestReportChecked.png\" alt=\"\"> <\/p><p>Alright, next you will need to create your runner with the right plugins. This is what you will want to run from your Jenkins build. Let's first set up the basic CI script. To include this information in your report, you will need two plugins on the TestRunner. First you will need the TestReportPlugin if you want a test report (makes sense I hope). Let's set this up to create an HTML report that we put into a \"reports\" subfolder of the Jenkins workspace:<\/p><pre class=\"codeinput\">import <span class=\"string\">matlab.unittest.*<\/span>;\r\nimport <span class=\"string\">matlab.unittest.plugins.*<\/span>;\r\n\r\nreportLocation = fullfile(getenv(<span class=\"string\">'WORKSPACE'<\/span>), <span class=\"string\">'reports'<\/span>);\r\n<span class=\"keyword\">if<\/span> ~isfolder(reportLocation)\r\n    mkdir(reportLocation);\r\n<span class=\"keyword\">end<\/span>\r\nrunner = TestRunner.withTextOutput;\r\nrunner.addPlugin(TestReportPlugin.producingHTML(reportLocation));\r\n<\/pre><p>Next, in order to get all of the Simulink Test specific details in the report, add the <a href=\"https:\/\/www.mathworks.com\/help\/sltest\/ref\/sltest.plugins.testmanagerresultsplugin-class.html\">TestManagerResultsPlugin<\/a> as well. Note, this plugin is included by default when using runtests, but it needs to be explicitly added here since we are configuring our own runner:<\/p><pre class=\"codeinput\">import <span class=\"string\">sltest.plugins.*<\/span>;\r\nrunner.addPlugin(TestManagerResultsPlugin);\r\n\r\nrunner.run(testsuite(testFile));\r\n<\/pre><pre class=\"codeoutput\">Running f14ParameterSweepTest &gt; New Test Suite 1\r\n.......... ........\r\n================================================================================\r\nVerification failed in f14ParameterSweepTest &gt; New Test Suite 1\/Iterations Parameter Sweep(ScriptedIteration=Scripted_Iteration19).\r\n\r\n    ---------------------\r\n    Framework Diagnostic:\r\n    ---------------------\r\n    Failed criteria: Baseline\r\n    --&gt; Logs:\r\n            Inputs may not be compatible for simulation. Test results might not be accurate. Click here for more information on external input mapping.\r\n    --&gt; Simulink Test Manager Results:\r\n            Results: 2018-Nov-13 13:07:03\/f14ParameterSweepTest\/New Test Suite 1\/Iterations Parameter Sweep\/Scripted_Iteration19\r\n================================================================================\r\n.. ...\r\n================================================================================\r\nVerification failed in f14ParameterSweepTest &gt; New Test Suite 1\/Iterations Parameter Sweep(ScriptedIteration=Scripted_Iteration24).\r\n\r\n    ---------------------\r\n    Framework Diagnostic:\r\n    ---------------------\r\n    Failed criteria: Baseline\r\n    --&gt; Logs:\r\n            Inputs may not be compatible for simulation. Test results might not be accurate. Click here for more information on external input mapping.\r\n    --&gt; Simulink Test Manager Results:\r\n            Results: 2018-Nov-13 13:07:03\/f14ParameterSweepTest\/New Test Suite 1\/Iterations Parameter Sweep\/Scripted_Iteration24\r\n================================================================================\r\n.\r\n================================================================================\r\nVerification failed in f14ParameterSweepTest &gt; New Test Suite 1\/Iterations Parameter Sweep(ScriptedIteration=Scripted_Iteration25).\r\n\r\n    ---------------------\r\n    Framework Diagnostic:\r\n    ---------------------\r\n    Failed criteria: Baseline\r\n    --&gt; Logs:\r\n            Inputs may not be compatible for simulation. Test results might not be accurate. Click here for more information on external input mapping.\r\n    --&gt; Simulink Test Manager Results:\r\n            Results: 2018-Nov-13 13:07:03\/f14ParameterSweepTest\/New Test Suite 1\/Iterations Parameter Sweep\/Scripted_Iteration25\r\n================================================================================\r\n.\r\nDone f14ParameterSweepTest &gt; New Test Suite 1\r\n__________\r\n\r\nFailure Summary:\r\n\r\n     Name                                                                                                         Failed  Incomplete  Reason(s)\r\n    ==========================================================================================================================================================\r\n     f14ParameterSweepTest &gt; New Test Suite 1\/Iterations Parameter Sweep(ScriptedIteration=Scripted_Iteration19)    X                 Failed by verification.\r\n    ----------------------------------------------------------------------------------------------------------------------------------------------------------\r\n     f14ParameterSweepTest &gt; New Test Suite 1\/Iterations Parameter Sweep(ScriptedIteration=Scripted_Iteration24)    X                 Failed by verification.\r\n    ----------------------------------------------------------------------------------------------------------------------------------------------------------\r\n     f14ParameterSweepTest &gt; New Test Suite 1\/Iterations Parameter Sweep(ScriptedIteration=Scripted_Iteration25)    X                 Failed by verification.\r\nGenerating report. Please wait.\r\n    Preparing content for the report.\r\n    Adding content to the report.\r\n    Writing report to file.\r\nReport has been saved to: \/private\/var\/folders\/bm\/6qgg87js1bb7fpr2p475bcwh0002wp\/T\/reports\/index.html\r\n<\/pre><p>Now when this test is run you will see the report generated with all its simulation data inspector based visual goodies, as well as other metadata specific to the Simulink Test. Here's one of the failures:<\/p><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"http:\/\/blogs.mathworks.com\/developer\/files\/y2018SLTestReportOutput.png\" alt=\"\"> <\/p><p>...zooming in you can see how the error between the actual and expected signals at around 20 seconds into the simulation was greater than the tolerance:<\/p><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"http:\/\/blogs.mathworks.com\/developer\/files\/y2018SLTestReportOutputZoomed.png\" alt=\"\"> <\/p><p>Now, you may want to save the resulting html in your Jenkins builds. You can, but you will either need to host your own web server to serve up the resulting html, or configure your Jenkins environment and leverage the <a href=\"https:\/\/wiki.jenkins.io\/display\/JENKINS\/HTML+Publisher+Plugin\">HTML Publisher Plugin<\/a> of Jenkins. The only issue with this is that you may need to make some changes to the Content Security Policy of your Jenkins server in order for these html reports to show correctly. You'll only want to do this if you have a good understanding of how your Jenkins server is configured and understand the security implications. A good overview of this is listed <a href=\"https:\/\/wiki.jenkins.io\/display\/JENKINS\/Configuring+Content+Security+Policy\">here<\/a>. However, the html test report won't be rendered correctly with the default Jenkins policy due to its use of JavaScript and CSS.<\/p><p>If you are able to safely configure the policy, however, you can see the report directly from your Jenkins builds:<\/p><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"http:\/\/blogs.mathworks.com\/developer\/files\/y2018SLTestReportJenkins.png\" alt=\"\"> <\/p><p>Isn't that lovely? Now you have a head start diagnosing the problem and getting the investigation into the right hands so you can focus on the amazing things you do!<\/p><script language=\"JavaScript\"> <!-- \r\n    function grabCode_48aa7c74979340c68a2d41ccf19f8f94() {\r\n        \/\/ Remember the title so we can use it in the new page\r\n        title = document.title;\r\n\r\n        \/\/ Break up these strings so that their presence\r\n        \/\/ in the Javascript doesn't mess up the search for\r\n        \/\/ the MATLAB code.\r\n        t1='48aa7c74979340c68a2d41ccf19f8f94 ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' 48aa7c74979340c68a2d41ccf19f8f94';\r\n    \r\n        b=document.getElementsByTagName('body')[0];\r\n        i1=b.innerHTML.indexOf(t1)+t1.length;\r\n        i2=b.innerHTML.indexOf(t2);\r\n \r\n        code_string = b.innerHTML.substring(i1, i2);\r\n        code_string = code_string.replace(\/REPLACE_WITH_DASH_DASH\/g,'--');\r\n\r\n        \/\/ Use \/x3C\/g instead of the less-than character to avoid errors \r\n        \/\/ in the XML parser.\r\n        \/\/ Use '\\x26#60;' instead of '<' so that the XML parser\r\n        \/\/ doesn't go ahead and substitute the less-than character. \r\n        code_string = code_string.replace(\/\\x3C\/g, '\\x26#60;');\r\n\r\n        copyright = 'Copyright 2018 The MathWorks, Inc.';\r\n\r\n        w = window.open();\r\n        d = w.document;\r\n        d.write('<pre>\\n');\r\n        d.write(code_string);\r\n\r\n        \/\/ Add copyright line at the bottom if specified.\r\n        if (copyright.length > 0) {\r\n            d.writeln('');\r\n            d.writeln('%%');\r\n            if (copyright.length > 0) {\r\n                d.writeln('% _' + copyright + '_');\r\n            }\r\n        }\r\n\r\n        d.write('<\/pre>\\n');\r\n\r\n        d.title = title + ' (MATLAB code)';\r\n        d.close();\r\n    }   \r\n     --> <\/script><p style=\"text-align: right; font-size: xx-small; font-weight:lighter;   font-style: italic; color: gray\"><br><a href=\"javascript:grabCode_48aa7c74979340c68a2d41ccf19f8f94()\"><span style=\"font-size: x-small;        font-style: italic;\">Get \r\n      the MATLAB code <noscript>(requires JavaScript)<\/noscript><\/span><\/a><br><br>\r\n      Published with MATLAB&reg; R2018b<br><\/p><\/div><!--\r\n48aa7c74979340c68a2d41ccf19f8f94 ##### SOURCE BEGIN #####\r\n%%\r\n% Hello all! I was reading up on Guy's blog the other day and remembered\r\n% his great post showing a\r\n% <https:\/\/blogs.mathworks.com\/simulink\/2018\/09\/04\/continuous-integration-with-simulink-project-and-simulink-test\/\r\n% Simulink Test workflow with Jenkins and GitLab>. One thing I thought was\r\n% cool in his musings was how he set it up to store the results so that you\r\n% didn't need to rerun the tests to begin investigating. \r\n%\r\n% Well I am happy to report that may be even easier in R2018b in your CI\r\n% workflows since the\r\n% <https:\/\/www.mathworks.com\/help\/matlab\/ref\/matlab.unittest.plugins.testreportplugin-class.html\r\n% TestReportPlugin> now includes all the Simulink Test specific information\r\n% in the report. This means that you can even begin to debug the problem or\r\n% get an idea of why the tests failed from directly in your browser by\r\n% looking at your CI dashboard. This then allows you to perhaps identify\r\n% the right person to further debug and fix the problem much more\r\n% efficiently. Just doin our part to keep your workflows well-oiled!\r\n%\r\n% This is really easy to do. To see it in action let's just look at one of\r\n% the Simulink Test examples, the f14ParameterSweepTest. This test has a\r\n% few failures that we can hopefully glean some quick insight into. To run\r\n% this as part of your CI build, you'll need to make a few quick\r\n% connections. First, for example, you'll want to ensure your Simulink Test\r\n% file(s) are configured to generate a report. Really all you'll need to do\r\n% is open the file in Test Manager and click the option to generate the\r\n% report:\r\n% \r\ntestFile = 'f14ParameterSweepTest.mldatx';\r\nsltest.testmanager.view;\r\nsltest.testmanager.load(testFile);\r\n\r\n%%\r\n% \r\n% <<y2018SLTestReportUnchecked.png>>\r\n%\r\n% Once this is checked you'll see some more options. You should just be\r\n% able to use the default selections to see the value here, but if you want\r\n% you can tweak what is included in the report.\r\n%\r\n% <<y2018SLTestReportChecked.png>>\r\n%\r\n% Alright, next you will need to create your runner with the right plugins.\r\n% This is what you will want to run from your Jenkins build. Let's first\r\n% set up the basic CI script. To include this information in your report,\r\n% you will need two plugins on the TestRunner. First you will need the\r\n% TestReportPlugin if you want a test report (makes sense I hope). Let's\r\n% set this up to create an HTML report that we put into a \"reports\"\r\n% subfolder of the Jenkins workspace:\r\nimport matlab.unittest.*;\r\nimport matlab.unittest.plugins.*;\r\n\r\nreportLocation = fullfile(getenv('WORKSPACE'), 'reports');\r\nif ~isfolder(reportLocation)\r\n    mkdir(reportLocation);\r\nend\r\nrunner = TestRunner.withTextOutput;\r\nrunner.addPlugin(TestReportPlugin.producingHTML(reportLocation));\r\n\r\n%%\r\n% Next, in order to get all of the Simulink Test specific details in the\r\n% report, add the\r\n% <https:\/\/www.mathworks.com\/help\/sltest\/ref\/sltest.plugins.testmanagerresultsplugin-class.html\r\n% TestManagerResultsPlugin> as well. Note, this plugin is included by\r\n% default when using runtests, but it needs to be explicitly added here\r\n% since we are configuring our own runner:\r\nimport sltest.plugins.*;\r\nrunner.addPlugin(TestManagerResultsPlugin);\r\n\r\nrunner.run(testsuite(testFile));\r\n\r\n%%\r\n% Now when this test is run you will see the report generated with all its\r\n% simulation data inspector based visual goodies, as well as other metadata\r\n% specific to the Simulink Test. Here's one of the failures:\r\n%\r\n% <<y2018SLTestReportOutput.png>>\r\n%\r\n% ...zooming in you can see how the error between the actual and expected\r\n% signals at around 20 seconds into the simulation was greater than the\r\n% tolerance:\r\n%\r\n% <<y2018SLTestReportOutputZoomed.png>>\r\n% \r\n% Now, you may want to save the resulting html in your Jenkins builds. You\r\n% can, but you will either need to host your own web server to serve up the\r\n% resulting html, or configure your Jenkins environment and leverage the\r\n% <https:\/\/wiki.jenkins.io\/display\/JENKINS\/HTML+Publisher+Plugin HTML\r\n% Publisher Plugin> of Jenkins. The only issue with this is that you may\r\n% need to make some changes to the Content Security Policy of your Jenkins\r\n% server in order for these html reports to show correctly. You'll only\r\n% want to do this if you have a good understanding of how your Jenkins\r\n% server is configured and understand the security implications. A good\r\n% overview of this is listed\r\n% <https:\/\/wiki.jenkins.io\/display\/JENKINS\/Configuring+Content+Security+Policy\r\n% here>. However, the html test report won't be rendered correctly with the\r\n% default Jenkins policy due to its use of JavaScript and CSS.\r\n%\r\n% If you are able to safely configure the policy, however, you can see the\r\n% report directly from your Jenkins builds:\r\n%\r\n% <<y2018SLTestReportJenkins.png>>\r\n%\r\n% Isn't that lovely? Now you have a head start diagnosing the problem and\r\n% getting the investigation into the right hands so you can focus on the\r\n% amazing things you do!\r\n\r\n\r\n\r\n##### SOURCE END ##### 48aa7c74979340c68a2d41ccf19f8f94\r\n-->","protected":false},"excerpt":{"rendered":"<div class=\"overview-image\"><img src=\"https:\/\/blogs.mathworks.com\/developer\/files\/y2018SLTestReportOutput.png\" class=\"img-responsive attachment-post-thumbnail size-post-thumbnail wp-post-image\" alt=\"\" decoding=\"async\" loading=\"lazy\" \/><\/div><p>Hello all! I was reading up on Guy's blog the other day and remembered his great post showing a Simulink Test workflow with Jenkins and GitLab. One thing I thought was cool in his musings was how he... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/developer\/2018\/11\/13\/simulink-test-html-report\/\">read more >><\/a><\/p>","protected":false},"author":90,"featured_media":1944,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[4],"tags":[],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/posts\/1938"}],"collection":[{"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/users\/90"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/comments?post=1938"}],"version-history":[{"count":3,"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/posts\/1938\/revisions"}],"predecessor-version":[{"id":1954,"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/posts\/1938\/revisions\/1954"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/media\/1944"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/media?parent=1938"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/categories?post=1938"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/tags?post=1938"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}