{"id":752,"date":"2016-10-31T14:50:40","date_gmt":"2016-10-31T14:50:40","guid":{"rendered":"https:\/\/blogs.mathworks.com\/developer\/?p=752"},"modified":"2016-10-31T16:21:25","modified_gmt":"2016-10-31T16:21:25","slug":"diagnostic-records","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/developer\/2016\/10\/31\/diagnostic-records\/","title":{"rendered":"Additional Ways to Consume the Secret Sauce"},"content":{"rendered":"<div class=\"content\"><p><i>For today's blog entry I'd like to introduce Stephen Carter. Stephen is an engineer on the MATLAB Test Frameworks team and has been involved in many exciting new features over the past few releases (and he continues working on more to come!). Stephen was excited to write a post or two to give you a few hints to help your test diagnostic workflows.<\/i><\/p><p>As Andy pointed out in a <a href=\"https:\/\/blogs.mathworks.com\/developer\/2016\/09\/29\/tap-with-yaml\/\">recent post<\/a>, we try to cook up our secret sauce in a way to make it taste just right. But is taste everything? For example, although Sam, from Dr Seuss's \"Green Eggs and Ham\", came to realize that he did in fact like to eat them in a boat, with a goat, in the rain, and on a train, I personally don't share the same viewpoint as Sam. Even if they are enjoyable on a boat or on a train, I don't think I would want them with a goat or in the rain.<\/p><p>What I am getting at is this: in addition to enhancing the diagnostics themselves, we recognize the need to continually provide additional ways for users to consume our diagnostics if they are to be useful for those with different preferences and use cases. Our <a href=\"https:\/\/blogs.mathworks.com\/developer\/category\/continuous-integration\/?s_tid=Blog_developer_Category\">recent posts<\/a> have been demonstrating ways to consume our diagnostics for the continuous integration use case. But there are a lot more use cases to consider.<\/p><p>First, let me start off with a scenario that some of you might relate to. You have just made some final changes to your source code and have already ran a handful of unit tests to give you some confidence to be able to run your full suite of tests before submitting your changes. You run the full suite using <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/runtests.html\">runtests<\/a>, which takes, let's say, five to ten minutes, and you see afterward that there are a few failures to address. From the MATLAB command window, you scroll up and find your first failure diagnostic and after reading it you try a few things at the command window to help you understand the failure better. And then of course you do what you always do when you are done playing around at the command window, and you type <tt>clc<\/tt> to <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/clc.html\">clear the window<\/a>.<\/p><p>Wait... what... oh no! You just lost your entire diagnostic output and you haven't even read the diagnostic messages for the other failures. At this point you are thinking, \"Do I really need to rerun my entire suite to find my failures?\".<\/p><p>Before rerunning your entire test suite, first check to see if you still have the <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/matlab.unittest.testresult-class.html\">TestResult<\/a> output that <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/runtests.html\">runtests<\/a> produced.<\/p><p>Prior to R2016a, you would see:<\/p><pre class=\"codeoutput\">     \r\nresults = \r\n\r\n  1x1151 TestResult array with properties:\r\n\r\n    Name\r\n    Passed\r\n    Failed\r\n    Incomplete\r\n    Duration\r\n \r\nTotals:\r\n   1148 Passed, 3 Failed, 0 Incomplete.\r\n   266.5616 seconds testing time.\r\n \r\n<\/pre><p>You'll notice that pass\/fail information is available. You can use this to shrink the test suite down so that you only have to rerun the tests that did not pass:<\/p><pre class=\"language-matlab\">\r\ndidNotPassResults = results(~[results.Passed]);\r\ntestsToRerun = {didNotPassResults.Name};\r\nruntests(testsToRerun); <span class=\"comment\">% Give me my diagnostics back!<\/span><\/pre><p>Starting in R2016a, we have provided a more efficient solution to this problem by serving up the diagnostics for you in a new way. You will now see the following <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/matlab.unittest.testresult-class.html\">TestResult<\/a> display:<\/p><pre class=\"codeinput\">results\r\n<\/pre><pre class=\"codeoutput\">\r\nresults = \r\n\r\n  1&times;1151 TestResult array with properties:\r\n\r\n    Name\r\n    Passed\r\n    Failed\r\n    Incomplete\r\n    Duration\r\n    Details\r\n\r\nTotals:\r\n   1148 Passed, 3 Failed, 0 Incomplete.\r\n   261.3082 seconds testing time.\r\n\r\n<\/pre><p>Do you see what's new? I'll give you a minute.... do you see the difference now? Ah yes, the new <tt>Details<\/tt> property. Let's take a look at the details of the first failing result:<\/p><pre class=\"codeinput\">firstFailingIndex = find([results.Failed],1);\r\nfirstFailingDetails = results(firstFailingIndex).Details\r\n<\/pre><pre class=\"codeoutput\">\r\nfirstFailingDetails = \r\n\r\n  struct with fields:\r\n\r\n    DiagnosticRecord: [1&times;1 matlab.unittest.plugins.diagnosticrecord.QualificationDiagnosticRecord]\r\n\r\n<\/pre><pre class=\"codeinput\">firstFailingDetails.DiagnosticRecord\r\n<\/pre><pre class=\"codeoutput\">\r\nans = \r\n\r\n  QualificationDiagnosticRecord with properties:\r\n\r\n         TestDiagnosticResult: {1&times;1 cell}\r\n    FrameworkDiagnosticResult: {'Negated IsSubsetOf failed....'}\r\n                        Stack: [1&times;1 struct]\r\n                        Event: 'VerificationFailed'\r\n                        Scope: 'ATitanicTest\/testAvoidanceSystem'\r\n                       Report: '==========================================...'\r\n\r\n<\/pre><pre class=\"codeinput\">firstFailingDetails.DiagnosticRecord.Report\r\n<\/pre><pre class=\"codeoutput\">\r\nans =\r\n\r\n================================================================================\r\nVerification failed in ATitanicTest\/testAvoidanceSystem.\r\n\r\n    ----------------\r\n    Test Diagnostic:\r\n    ----------------\r\n    Let's try to avoid hitting things that could end in disaster.\r\n\r\n    ---------------------\r\n    Framework Diagnostic:\r\n    ---------------------\r\n    Negated IsSubsetOf failed.\r\n    --&gt; The actual value is a subset of the prohibited superset.\r\n    \r\n    Actual Value (cell):\r\n            'iceberg'\r\n    Prohibited Superset (cell):\r\n            'land'    'iceberg'    'boat'\r\n\r\n    ------------------\r\n    Stack Information:\r\n    ------------------\r\n    In H:\\Documents\\MATLAB\\SecretSauce\\ATitanicTest.m (ATitanicTest.testAvoidanceSystem) at 5\r\n================================================================================\r\n\r\n\r\n<\/pre><p>As you can see, <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/runtests.html\">runtests<\/a> now captures failing diagnostics on the <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/matlab.unittest.testresult-class.html\">TestResult<\/a> output. The driving force behind this is actually a new <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/matlab.unittest.plugins.diagnosticsrecordingplugin-class.html\">DiagnosticsRecordingPlugin<\/a>. Manually adding this plugin provides users with even more options, like recording passing diagnostics and controlling the verbosity at which logged diagnostics are recorded.<\/p><p>For example, to record passing diagnostics you can do the following:<\/p><pre class=\"language-matlab\">\r\nimport <span class=\"string\">matlab.unittest.TestRunner<\/span>;\r\nimport <span class=\"string\">matlab.unittest.plugins.DiagnosticsRecordingPlugin<\/span>;\r\n\r\nrunner = TestRunner.withTextOutput;\r\nplugin = DiagnosticsRecordingPlugin(<span class=\"string\">'IncludingPassingDiagnostics'<\/span>,true);\r\nrunner.addPlugin(plugin);\r\n\r\nresults = runner.run(testsuite);<\/pre><p>Now we can find the first passing diagnostic recorded:<\/p><pre class=\"codeinput\">allDetails = [results.Details];\r\nallDiagnosticRecords = [allDetails.DiagnosticRecord]\r\npassedRecords = selectPassed(allDiagnosticRecords)\r\npassedRecords(1) <span class=\"comment\">% look at the record for the first passing event<\/span>\r\n<\/pre><pre class=\"codeoutput\">\r\nallDiagnosticRecords = \r\n\r\n  1&times;1151 QualificationDiagnosticRecord array with properties:\r\n\r\n    TestDiagnosticResult\r\n    FrameworkDiagnosticResult\r\n    Stack\r\n    Event\r\n    Scope\r\n    Report\r\n\r\n\r\npassedRecords = \r\n\r\n  1&times;1148 QualificationDiagnosticRecord array with properties:\r\n\r\n    TestDiagnosticResult\r\n    FrameworkDiagnosticResult\r\n    Stack\r\n    Event\r\n    Scope\r\n    Report\r\n\r\n\r\nans = \r\n\r\n  QualificationDiagnosticRecord with properties:\r\n\r\n         TestDiagnosticResult: {}\r\n    FrameworkDiagnosticResult: {'IsEqualTo passed....'}\r\n                        Stack: [1&times;1 struct]\r\n                        Event: 'VerificationPassed'\r\n                        Scope: 'CapitalGroupStrategyTest\/testStockTicker'\r\n                       Report: '==========================================...'\r\n\r\n<\/pre><pre class=\"codeinput\">passedRecords(1).Report\r\n<\/pre><pre class=\"codeoutput\">\r\nans =\r\n\r\n================================================================================\r\nVerification passed in CapitalGroupStrategyTest\/testStockTicker.\r\n\r\n    ---------------------\r\n    Framework Diagnostic:\r\n    ---------------------\r\n    IsEqualTo passed.\r\n    --&gt; StringComparator passed.\r\n        --&gt; The character arrays are equal (ignoring case).\r\n        \r\n        Actual char:\r\n            Goog\r\n        Expected char:\r\n            GOOG\r\n\r\n    ------------------\r\n    Stack Information:\r\n    ------------------\r\n    In H:\\Documents\\MATLAB\\SecretSauce\\CapitalGroupStrategyTest.m (CapitalGroupStrategyTest.testStockTicker) at 5\r\n================================================================================\r\n\r\n\r\n<\/pre><p>Stay tuned for even more ways to consume our secret sauce.<\/p><script language=\"JavaScript\"> <!-- \r\n    function grabCode_72a16c0d2a8748dcba0d4baec7ef1d91() {\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='72a16c0d2a8748dcba0d4baec7ef1d91 ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' 72a16c0d2a8748dcba0d4baec7ef1d91';\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 2016 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_72a16c0d2a8748dcba0d4baec7ef1d91()\"><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; R2016b<br><\/p><\/div><!--\r\n72a16c0d2a8748dcba0d4baec7ef1d91 ##### SOURCE BEGIN #####\r\n%%\r\n% _For today's blog entry I'd like to introduce Stephen Carter. Stephen is\r\n% an engineer on the MATLAB Test Frameworks team and has been involved in\r\n% many exciting new features over the past few releases (and he continues\r\n% working on more to come!). Stephen was excited to write a post or two to\r\n% give you a few hints to help your test diagnostic workflows._\r\n%\r\n% As Andy pointed out in a\r\n% <https:\/\/blogs.mathworks.com\/developer\/2016\/09\/29\/tap-with-yaml\/ recent\r\n% post>, we try to cook up our secret sauce in a way to make it taste just\r\n% right. But is taste everything? For example, although Sam, from Dr\r\n% Seuss's \"Green Eggs and Ham\", came to realize that he did in fact like to\r\n% eat them in a boat, with a goat, in the rain, and on a train, I\r\n% personally don't share the same viewpoint as Sam. Even if they are\r\n% enjoyable on a boat or on a train, I don't think I would want them with a\r\n% goat or in the rain.\r\n%\r\n% What I am getting at is this: in addition to enhancing the diagnostics\r\n% themselves, we recognize the need to continually provide additional ways\r\n% for users to consume our diagnostics if they are to be useful for\r\n% those with different preferences and use cases. Our\r\n% <https:\/\/blogs.mathworks.com\/developer\/category\/continuous-integration\/?s_tid=Blog_developer_Category\r\n% recent posts> have been demonstrating ways to consume our diagnostics for\r\n% the continuous integration use case. But there are a lot more use cases\r\n% to consider.\r\n%\r\n% First, let me start off with a scenario that some of you might relate to.\r\n% You have just made some final changes to your source code and have\r\n% already ran a handful of unit tests to give you some confidence to be\r\n% able to run your full suite of tests before submitting your changes. You\r\n% run the full suite using\r\n% <https:\/\/www.mathworks.com\/help\/matlab\/ref\/runtests.html runtests>, which\r\n% takes, let's say, five to ten minutes, and you see afterward that there are\r\n% a few failures to address. From the MATLAB command window, you\r\n% scroll up and find your first failure diagnostic and after reading it you\r\n% try a few things at the command window to help you understand the failure\r\n% better. And then of course you do what you always do when you are done\r\n% playing around at the command window, and you type |clc| to\r\n% <https:\/\/www.mathworks.com\/help\/matlab\/ref\/clc.html clear the window>.\r\n%\r\n% Wait... what... oh no! You just lost your entire diagnostic\r\n% output and you haven't even read the diagnostic messages for the other\r\n% failures. At this point you are thinking, \"Do I really need to rerun\r\n% my entire suite to find my failures?\".\r\n%\r\n% Before rerunning your entire test suite, first check to see if you still\r\n% have the\r\n% <https:\/\/www.mathworks.com\/help\/matlab\/ref\/matlab.unittest.testresult-class.html\r\n% TestResult> output that\r\n% <https:\/\/www.mathworks.com\/help\/matlab\/ref\/runtests.html runtests>\r\n% produced.\r\n% \r\n% Prior to R2016a, you would see:\r\n% \r\nload('resultsFile.mat')\r\ndisp(pre16aResults)\r\n% DELETE ME BEFORE POSTING\r\n\r\n%%\r\n% You'll notice that pass\/fail information is available. You can use this\r\n% to shrink the test suite down so that you only have to rerun the tests\r\n% that did not pass:\r\n%\r\n% <include>rerunScript.m<\/include>\r\n%\r\n% Starting in R2016a, we have provided a more efficient solution to this\r\n% problem by serving up the diagnostics for you in a new way. You will now\r\n% see the following\r\n% <https:\/\/www.mathworks.com\/help\/matlab\/ref\/matlab.unittest.testresult-class.html\r\n% TestResult> display:\r\nresults\r\n\r\n%% \r\n% Do you see what's new? I'll give you a minute.... do you see the difference now? Ah yes, the new |Details|\r\n% property. Let's take a look at the details of the first failing result:\r\n%\r\nfirstFailingIndex = find([results.Failed],1);\r\nfirstFailingDetails = results(firstFailingIndex).Details\r\n\r\n%%\r\nfirstFailingDetails.DiagnosticRecord\r\n\r\n%%\r\nfirstFailingDetails.DiagnosticRecord.Report\r\n\r\n%%\r\n% As you can see, <https:\/\/www.mathworks.com\/help\/matlab\/ref\/runtests.html\r\n% runtests> now captures failing diagnostics on the\r\n% <https:\/\/www.mathworks.com\/help\/matlab\/ref\/matlab.unittest.testresult-class.html\r\n% TestResult> output. The driving force behind this is actually a new\r\n% <https:\/\/www.mathworks.com\/help\/matlab\/ref\/matlab.unittest.plugins.diagnosticsrecordingplugin-class.html\r\n% DiagnosticsRecordingPlugin>. Manually adding this plugin provides users\r\n% with even more options, like recording passing diagnostics and\r\n% controlling the verbosity at which logged diagnostics are recorded.\r\n%\r\n% For example, to record passing diagnostics you can do the following:\r\n%\r\n% <include>recordPassingDiagnostics.m<\/include>\r\n%\r\n% Now we can find the first passing diagnostic recorded:\r\nallDetails = [results.Details];\r\nallDiagnosticRecords = [allDetails.DiagnosticRecord]\r\npassedRecords = selectPassed(allDiagnosticRecords)\r\npassedRecords(1) % look at the record for the first passing event\r\n%%\r\npassedRecords(1).Report\r\n%%\r\n% Stay tuned for even more ways to consume our secret sauce.\r\n##### SOURCE END ##### 72a16c0d2a8748dcba0d4baec7ef1d91\r\n-->","protected":false},"excerpt":{"rendered":"<div class=\"overview-image\"><img src=\"https:\/\/blogs.mathworks.com\/developer\/files\/2016SecretSauce.jpeg\" class=\"img-responsive attachment-post-thumbnail size-post-thumbnail wp-post-image\" alt=\"\" decoding=\"async\" loading=\"lazy\" \/><\/div><p>For today's blog entry I'd like to introduce Stephen Carter. Stephen is an engineer on the MATLAB Test Frameworks team and has been involved in many exciting new features over the past few releases... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/developer\/2016\/10\/31\/diagnostic-records\/\">read more >><\/a><\/p>","protected":false},"author":90,"featured_media":793,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[7],"tags":[],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/posts\/752"}],"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=752"}],"version-history":[{"count":21,"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/posts\/752\/revisions"}],"predecessor-version":[{"id":797,"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/posts\/752\/revisions\/797"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/media\/793"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/media?parent=752"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/categories?post=752"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/tags?post=752"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}