{"id":249,"date":"2015-09-08T21:41:17","date_gmt":"2015-09-08T21:41:17","guid":{"rendered":"https:\/\/blogs.mathworks.com\/developer\/?p=249"},"modified":"2015-09-09T14:19:17","modified_gmt":"2015-09-09T14:19:17","slug":"test-tags","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/developer\/2015\/09\/08\/test-tags\/","title":{"rendered":"Tag, you&#8217;re it!"},"content":{"rendered":"\r\n\r\n<div class=\"content\"><!--introduction--><!--\/introduction--><p>I have found that with any reasonably sized software project, sooner or later organization becomes important. As additional features and capabilities are introduced into a toolbox it becomes important to quickly and easily get your hands on the right piece of code for the task at hand. When we are talking about these software products, often times a piece of code does \"double duty\" so to speak. For these it is not uncommon that a single class or function or method is generalized to correctly serve many use cases.<\/p><p>How do we narrow down on these snippets of code? The tests of course! While a single bit of source code may be general enough to fulfill many use cases, the tests should be written to ensure each use case and user visible feature works correctly. In other words, if you want each use case to be covered, it had better have its corresponding tests, even if the implementation is covered via some generalized mechanism in the source code.<\/p><p>OK, easy enough. We'll use the tests and it will always be trivial to locate the specific tests we need right? Ummmmmm, no. Tests themselves are source code and will have the same issues with transparency as the source code they apply to. Because of this it is fairly common to see the tests themselves organized into some structure that attempts to categorize them for easy retrieval. Do I want to run the unit tests for the numeric foundations of my product? Just go to the <tt>tests\/numerics\/unit<\/tt> folder and type <b><tt>runtests<\/tt><\/b>. How about the tests that exercise these numerics through my user interface? Perhaps these are placed in the <tt>tests.system.ui<\/tt> test package? OK, maybe there's a lot of system testing debris in there that don't have to do with numerics but whatevs, deal with it!<\/p><p>What if I want to find the tests\/code that covers the integration of my classification features and my persistence? For example lets say you perform a classification and save the results to some form of persistence such as a database or mat file. Well, hmm how do we find those tests? Will they be in <tt>tests\/classification<\/tt> or <tt>tests\/persistence<\/tt>? If they are in one folder but not the other does this mean that one of these test folders is the true \"owner\" of the feature and the other is not, relegated to a life of underachievement and low self-esteem?<\/p><p>Not so! I am here to defend these poor test folders! I am here to declare upon the rooftops that if you didn't categorize your system perfectly not all hope is lost. I understand that categorizing things correctly is <a href=\"https:\/\/blogs.mathworks.com\/developer\/2015\/03\/31\/dont-get-in-too-deep\/\">very hard to do<\/a>.<\/p><p>Can we please de-emphasize hierarchies based on folder or package structure? Instead wouldn't it be great if we could tag specific test content with meta data for use in categorization? This meta data could then apply to test content across different axes, features, or viewpoints, unlike folders or package structures. You can't place a file in two folders at the same time. Instead lets spend most of our organizational time on figuring out the best categories for our test code.<\/p><p>If you have R2015a or later this can be done easily using the <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/matlab_prog\/tag-unit-tests.html\">test tagging features<\/a> of the test framework.<\/p><p>This test tagging feature is a bit like labels in Gmail&#8482;, wherein you can apply certain labels to incoming mail messages and subsequently filter your messages using this label.<\/p><p>How might we apply this in our test content?<\/p><p>Well first let's look at a couple different axes that would be sure to get us into trouble trying to design inside a hierarchy. If we just stick with the examples already discussed, perhaps we might have some test classes that look like those below. Note these tests contain a bit of pseudocode and don't run since the product we are testing doesn't really exist.<\/p><pre class=\"language-matlab\">\r\n<span class=\"keyword\">classdef<\/span> (TestTags = {<span class=\"string\">'Classification'<\/span>, <span class=\"string\">'Persistence'<\/span>}) ClassificationWithPersistenceTest &lt; matlab.unittest.TestCase\r\n    <span class=\"comment\">% This test exercises how two features of my toolbox work together, namely<\/span>\r\n    <span class=\"comment\">% how the toolbox classification features work with persistence handling.<\/span>\r\n    \r\n    <span class=\"keyword\">methods<\/span>(Test)\r\n        <span class=\"keyword\">function<\/span> testClassificationResultSavedCorrectly(testCase)\r\n            \r\n            <span class=\"comment\">% Classify some data and persist the result<\/span>\r\n            data = load(<span class=\"string\">'testData.mat'<\/span>);\r\n            classification = classify(data);\r\n            classification.persist(<span class=\"string\">'testFile.mat'<\/span>); \r\n            \r\n            result = load(<span class=\"string\">'testFile.mat'<\/span>);\r\n            \r\n            testCase.verifyEqual(result, classification, <span class=\"keyword\">...<\/span>\r\n                <span class=\"string\">'The classification did not persist correctly in the mat file.'<\/span>);\r\n\r\n        <span class=\"keyword\">end<\/span>\r\n    <span class=\"keyword\">end<\/span>\r\n<span class=\"keyword\">end<\/span>  \r\n\r\n<\/pre><p>Note this test class has an additional <b><tt>TestTags<\/tt><\/b> attribute on the classdef block. In that attribute you can list some tags that will help identify the intended purpose(s) of the test. In this case we can identify this test as related to both the <tt>'Classification'<\/tt> and <tt>'Persistence'<\/tt> features.<\/p><p>This is fun, lets do some more:<\/p><pre class=\"language-matlab\">\r\n<span class=\"keyword\">classdef<\/span> (TestTags = {<span class=\"string\">'Numerics'<\/span>}) CoreNumericsUnitTest &lt; matlab.unittest.TestCase\r\n    <span class=\"comment\">% Here is a unit test of the core numerics of my toolbox<\/span>\r\n    \r\n    <span class=\"keyword\">methods<\/span>(Test)\r\n        <span class=\"keyword\">function<\/span> testCoreNumerics(testCase)\r\n            input = 1:10;\r\n            actual = CoreNumericEngine.analyze(input);\r\n            expected = expectedResultFromFirstPrinciples(input);\r\n            \r\n            testCase.verifyEqual(actual, expected, <span class=\"string\">'RelTol'<\/span>, sqrt(eps));\r\n        <span class=\"keyword\">end<\/span>\r\n    <span class=\"keyword\">end<\/span>\r\n<span class=\"keyword\">end<\/span>  \r\n\r\n<\/pre><p>Now we have a nice beautiful numerics unit test. How about that system test we talked about?<\/p><pre class=\"language-matlab\">\r\n<span class=\"keyword\">classdef<\/span> (TestTags = {<span class=\"string\">'UI'<\/span>}) AcceptanceSystemTest &lt; matlab.unittest.TestCase\r\n    <span class=\"comment\">% A system test exercising the full stack of my app with a focus on<\/span>\r\n    <span class=\"comment\">% priority customer workflows.<\/span>\r\n    \r\n    <span class=\"keyword\">methods<\/span>(Test, TestTags = {<span class=\"string\">'Persistence'<\/span>})\r\n        <span class=\"keyword\">function<\/span> testApplicationImportData(testCase)\r\n            fig = numericsapp;\r\n            clickImportButtonAndSelect(<span class=\"string\">'testFile.mat'<\/span>);\r\n            \r\n            classification = getClassificationfromUI(fig);\r\n            expected = load(<span class=\"string\">'testFile.mat'<\/span>);\r\n            testCase.verifyEqual(classification, expected, <span class=\"keyword\">...<\/span>\r\n                <span class=\"string\">'Classification data not imported correctly into the app.'<\/span>);\r\n        <span class=\"keyword\">end<\/span>\r\n    <span class=\"keyword\">end<\/span>\r\n    \r\n    <span class=\"keyword\">methods<\/span>(Test, TestTags = {<span class=\"string\">'Numerics'<\/span>})\r\n        <span class=\"keyword\">function<\/span> testApplicationNumericResults(testCase)\r\n            fig = numericsapp;\r\n            clickAnalyzeButton(fig);\r\n            \r\n            actual = getCurrentResult(fig);\r\n            expected = CoreNumericEngine.analyze(getCurrentData(fig));\r\n            testCase.verifyEqual(actual, expected, <span class=\"keyword\">...<\/span>\r\n                <span class=\"string\">'App results do not match numeric counterpart.'<\/span>);\r\n        <span class=\"keyword\">end<\/span>\r\n    <span class=\"keyword\">end<\/span>\r\n<span class=\"keyword\">end<\/span>\r\n\r\n<\/pre><p>This test was a bit different, as you can see the <b><tt>TestTags<\/tt><\/b> attribute is not only on the classdef block, but is included on the test methods block as well. Well, ultimately these tags apply to test methods, but including <b><tt>TestTags<\/tt><\/b> on the classdef block is a sort of shorthand for applying the tags to all of the methods of that class (and all subclasses if any). The first two test examples clearly wanted these tags applied to all methods of the class. However, system testing, in particular is a bit more nuanced. System tests can span the full feature set of a toolbox, and it is not uncommon for different tests to touch different portions of the toolbox functionality. In this case, both test methods are <tt>'UI'<\/tt> but only one of them deals with <tt>'Persistence'<\/tt> and one with <tt>'Numerics'<\/tt>. Applying the tags at the method level allows us to differentiate these two.<\/p><p>Well alright, what does this give us? Test selection anyone? Let's look at our full suite containing all these tests:<\/p><pre class=\"codeinput\">import <span class=\"string\">matlab.unittest.TestSuite<\/span>;\r\nfullSuite = TestSuite.fromFolder(<span class=\"string\">'tests'<\/span>)\r\n<\/pre><pre class=\"codeoutput\">\r\nfullSuite = \r\n\r\n  1x4 Test array with properties:\r\n\r\n    Name\r\n    Parameterization\r\n    SharedTestFixtures\r\n    Tags\r\n\r\nTests Include:\r\n   0 Parameterizations, 0 Shared Test Fixture Classes, 4 Unique Tags.\r\n\r\n<\/pre><p>The careful reader will note that this suite's display actually shows <tt>4 Unique Tags<\/tt>. If you are running in MATLAB this is actually a hyperlink that shows you the full list of tags contained in the suite. When clicked it looks something like:<\/p><pre>         Tag\r\n   ________________\r\n   'Classification'\r\n   'Numerics'\r\n   'Persistence'\r\n   'UI'<\/pre><p>Now here's a quick way to see which tests we are working with in a suite. It is a concise way to place the names of each suite element into a column cell array which displays nicely.<\/p><pre class=\"codeinput\">{fullSuite.Name}.'\r\n<\/pre><pre class=\"codeoutput\">\r\nans = \r\n\r\n    'AcceptanceSystemTest\/testApplicationNumericResults'\r\n    'AcceptanceSystemTest\/testApplicationImportData'\r\n    'ClassificationWithPersistenceTest\/testClassificationResultSavedCorrectly'\r\n    'CoreNumericsUnitTest\/testCoreNumerics'\r\n\r\n<\/pre><p>Now we can slice and dice this suite however we want based on our tags using the nice <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/matlab.unittest.testsuite.selectif.html\">selectIf<\/a> method:<\/p><pre class=\"codeinput\">persistenceSuite = fullSuite.selectIf(<span class=\"string\">'Tag'<\/span>,<span class=\"string\">'Persistence'<\/span>);\r\n{persistenceSuite.Name}.'\r\n<\/pre><pre class=\"codeoutput\">\r\nans = \r\n\r\n    'AcceptanceSystemTest\/testApplicationImportData'\r\n    'ClassificationWithPersistenceTest\/testClassificationResultSavedCorrectly'\r\n\r\n<\/pre><p>It even supports wildcards:<\/p><pre class=\"codeinput\">numericsSuite = fullSuite.selectIf(<span class=\"string\">'Tag'<\/span>,<span class=\"string\">'Num*'<\/span>);\r\n{numericsSuite.Name}.'\r\n<\/pre><pre class=\"codeoutput\">\r\nans = \r\n\r\n    'AcceptanceSystemTest\/testApplicationNumericResults'\r\n    'CoreNumericsUnitTest\/testCoreNumerics'\r\n\r\n<\/pre><p>Finally, one of the huge benefits of tagging tests like this is that you don't need to  commit to only one axis to categorize your test content. This example has shown adding specific tags according to features of the toolbox. However, we could also take the type of test as another axis we may want to work with. For example, if you are a fan of Google's <a href=\"http:\/\/googletesting.blogspot.com\/2010\/12\/test-sizes.html\">small\/medium\/large<\/a> test nomenclature you may want to set up a CI system to run small tests for every check-in, medium tests every night, and large tests at the end of each iteration. This deferred testing strategy becomes very easy with the aid of test tags. Let's add <tt>'Small'<\/tt>, <tt>'Medium'<\/tt>, and <tt>'Large'<\/tt> tags.<\/p><pre class=\"language-matlab\">\r\n<span class=\"keyword\">classdef<\/span> (TestTags = {<span class=\"string\">'Classification'<\/span>, <span class=\"string\">'Persistence'<\/span>, <span class=\"string\">'Medium'<\/span>}) ClassificationWithPersistenceTest &lt; matlab.unittest.TestCase\r\n    <span class=\"comment\">% This test exercises how two features of my toolbox work together, namely<\/span>\r\n    <span class=\"comment\">% how the toolbox classification features work with persistence handling.<\/span>\r\n    \r\n    <span class=\"keyword\">methods<\/span>(Test)\r\n        <span class=\"keyword\">function<\/span> testClassificationResultSavedCorrectly(testCase)\r\n            \r\n            <span class=\"comment\">% Classify some data and persist the result<\/span>\r\n            data = load(<span class=\"string\">'testData.mat'<\/span>);\r\n            classification = classify(data);\r\n            classification.persist(<span class=\"string\">'testFile.mat'<\/span>); \r\n            \r\n            result = load(<span class=\"string\">'testFile.mat'<\/span>);\r\n            \r\n            testCase.verifyEqual(result, classification, <span class=\"keyword\">...<\/span>\r\n                <span class=\"string\">'The classification did not persist correctly in the mat file.'<\/span>);\r\n\r\n        <span class=\"keyword\">end<\/span>\r\n    <span class=\"keyword\">end<\/span>\r\n<span class=\"keyword\">end<\/span>\r\n\r\n\r\n\r\n<span class=\"keyword\">classdef<\/span> (TestTags = {<span class=\"string\">'Numerics'<\/span>, <span class=\"string\">'Small'<\/span>}) CoreNumericsUnitTest &lt; matlab.unittest.TestCase\r\n    <span class=\"comment\">% Here is a unit test of the core numerics of my toolbox<\/span>\r\n    \r\n    <span class=\"keyword\">methods<\/span>(Test)\r\n        <span class=\"keyword\">function<\/span> testCoreNumerics(testCase)\r\n            input = 1:10;\r\n            actual = CoreNumericEngine.analyze(input);\r\n            expected = expectedResultFromFirstPrinciples(input);\r\n            \r\n            testCase.verifyEqual(actual, expected, <span class=\"string\">'RelTol'<\/span>, sqrt(eps));\r\n        <span class=\"keyword\">end<\/span>\r\n    <span class=\"keyword\">end<\/span>\r\n<span class=\"keyword\">end<\/span>\r\n\r\n\r\n\r\n<span class=\"keyword\">classdef<\/span> (TestTags = {<span class=\"string\">'UI'<\/span>,<span class=\"string\">'Large'<\/span>}) AcceptanceSystemTest &lt; matlab.unittest.TestCase\r\n    <span class=\"comment\">% A system test exercising the full stack of my app with a focus on<\/span>\r\n    <span class=\"comment\">% priority customer workflows.<\/span>\r\n    \r\n    <span class=\"keyword\">methods<\/span>(Test, TestTags = {<span class=\"string\">'Persistence'<\/span>})\r\n        <span class=\"keyword\">function<\/span> testApplicationImportData(testCase)\r\n            fig = numericsapp;\r\n            clickImportButtonAndSelect(<span class=\"string\">'testFile.mat'<\/span>);\r\n            \r\n            classification = getClassificationfromUI(fig);\r\n            expected = load(<span class=\"string\">'testFile.mat'<\/span>);\r\n            testCase.verifyEqual(classification, expected, <span class=\"keyword\">...<\/span>\r\n                <span class=\"string\">'Classification data not imported correctly into the app.'<\/span>);\r\n        <span class=\"keyword\">end<\/span>\r\n    <span class=\"keyword\">end<\/span>\r\n    \r\n    <span class=\"keyword\">methods<\/span>(Test, TestTags = {<span class=\"string\">'Numerics'<\/span>})\r\n        <span class=\"keyword\">function<\/span> testApplicationNumericResults(testCase)\r\n            fig = numericsapp;\r\n            clickAnalyzeButton(fig);\r\n            \r\n            actual = getCurrentResult(fig);\r\n            expected = CoreNumericEngine.analyze(getCurrentData(fig));\r\n            testCase.verifyEqual(actual, expected, <span class=\"keyword\">...<\/span>\r\n                <span class=\"string\">'App results do not match numeric counterpart.'<\/span>);\r\n        <span class=\"keyword\">end<\/span>\r\n    <span class=\"keyword\">end<\/span>   \r\n<span class=\"keyword\">end<\/span>\r\n\r\n<\/pre><p>We can even prefilter these tests in test suite creation methods like fromFolder:<\/p><pre class=\"codeinput\">smallTests = TestSuite.fromFolder(<span class=\"string\">'tests\/v2'<\/span>, <span class=\"string\">'Tag'<\/span>, <span class=\"string\">'Small'<\/span>);\r\n{smallTests.Name}.'\r\n\r\nmediumTests = TestSuite.fromFolder(<span class=\"string\">'tests\/v2'<\/span>, <span class=\"string\">'Tag'<\/span>, <span class=\"string\">'Medium'<\/span>);\r\n{mediumTests.Name}.'\r\n\r\nlargeTests = TestSuite.fromFolder(<span class=\"string\">'tests\/v2'<\/span>, <span class=\"string\">'Tag'<\/span>, <span class=\"string\">'Large'<\/span>);\r\n{largeTests.Name}.'\r\n<\/pre><pre class=\"codeoutput\">\r\nans = \r\n\r\n    'CoreNumericsUnitTest\/testCoreNumerics'\r\n\r\n\r\nans = \r\n\r\n    'ClassificationWithPersistenceTest\/testClassificationResultSavedCorrectly'\r\n\r\n\r\nans = \r\n\r\n    'AcceptanceSystemTest\/testApplicationNumericResults'\r\n    'AcceptanceSystemTest\/testApplicationImportData'\r\n\r\n<\/pre><p>A key point here is that while this test suite is very small and manageable, this definitely does not hold in any serious software development project. Using test tags is a nice way to avoid relying too much on limited folder or package structure for test organization, instead favoring tagging each test along whichever axes it belongs to.<\/p><p>Then when you are looking for exactly the right set of tests to exercise exactly the right pieces of your software product......(wait for it)....<\/p><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/developer\/files\/2015TagYoureIt.png\" alt=\"\"> <\/p><script language=\"JavaScript\"> <!-- \r\n    function grabCode_fed0e2aae58b4a89920f579a202ade3e() {\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='fed0e2aae58b4a89920f579a202ade3e ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' fed0e2aae58b4a89920f579a202ade3e';\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 2015 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_fed0e2aae58b4a89920f579a202ade3e()\"><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; R2015b<br><\/p><\/div><!--\r\nfed0e2aae58b4a89920f579a202ade3e ##### SOURCE BEGIN #####\r\n%% Tag, you're it!\r\n%%\r\n% I have found that with any reasonably sized software project, sooner or\r\n% later organization becomes important. As additional features and\r\n% capabilities are introduced into a toolbox it becomes important to\r\n% quickly and easily get your hands on the right piece of code for the task\r\n% at hand. When we are talking about these software products, often times a\r\n% piece of code does \"double duty\" so to speak. For these it is not\r\n% uncommon that a single class or function or method is generalized to\r\n% correctly serve many use cases.\r\n%\r\n% How do we narrow down on these snippets of code? The tests of course!\r\n% While a single bit of source code may be general enough to fulfill many\r\n% use cases, the tests should be written to ensure each use case and user\r\n% visible feature works correctly. In other words, if you want each use\r\n% case to be covered, it had better have its corresponding tests, even if\r\n% the implementation is covered via some generalized mechanism in the\r\n% source code.\r\n%\r\n% OK, easy enough. We'll use the tests and it will always be trivial to\r\n% locate the specific tests we need right? Ummmmmm, no. Tests themselves\r\n% are source code and will have the same issues with transparency as the\r\n% source code they apply to. Because of this it is fairly common to see the\r\n% tests themselves organized into some structure that attempts to\r\n% categorize them for easy retrieval. Do I want to run the unit tests for\r\n% the numeric foundations of my product? Just go to the\r\n% |tests\/numerics\/unit| folder and type *|runtests|*. How about the tests\r\n% that exercise these numerics through my user interface? Perhaps these are\r\n% placed in the |tests.system.ui| test package? OK, maybe there's a lot of\r\n% system testing debris in there that don't have to do with numerics but\r\n% whatevs, deal with it!\r\n%\r\n% What if I want to find the tests\/code that covers the integration of my\r\n% classification features and my persistence? For example lets say you\r\n% perform a classification and save the results to some form of persistence\r\n% such as a database or mat file. Well, hmm how do we find those tests?\r\n% Will they be in |tests\/classification| or |tests\/persistence|? If they\r\n% are in one folder but not the other does this mean that one of these test\r\n% folders is the true \"owner\" of the feature and the other is not,\r\n% relegated to a life of underachievement and low self-esteem?\r\n%\r\n% Not so! I am here to defend these poor test folders! I am here to declare\r\n% upon the rooftops that if you didn't categorize your system perfectly not\r\n% all hope is lost. I understand that categorizing things correctly is\r\n% <https:\/\/blogs.mathworks.com\/developer\/2015\/03\/31\/dont-get-in-too-deep\/\r\n% very hard to do>.\r\n%\r\n% Can we please de-emphasize hierarchies based on folder or package\r\n% structure? Instead wouldn't it be great if we could tag specific test\r\n% content with meta data for use in categorization? This meta data could\r\n% then apply to test content across different axes, features, or\r\n% viewpoints, unlike folders or package structures. You can't place a file\r\n% in two folders at the same time. Instead lets spend most of our\r\n% organizational time on figuring out the best categories for our test\r\n% code.\r\n%\r\n% If you have R2015a or later this can be done easily using the\r\n% <https:\/\/www.mathworks.com\/help\/matlab\/matlab_prog\/tag-unit-tests.html\r\n% test tagging features> of the test framework.\r\n%\r\n% This test tagging feature is a bit like labels in Gmail(TM), wherein you\r\n% can apply certain labels to incoming mail messages and subsequently \r\n% filter your messages using this label.\r\n%\r\n% How might we apply this in our test content?\r\n%\r\n% Well first let's look at a couple different axes that would be sure to\r\n% get us into trouble trying to design inside a hierarchy. If we just stick\r\n% with the examples already discussed, perhaps we might have some test\r\n% classes that look like those below. Note these tests contain a bit of\r\n% pseudocode and don't run since the product we are testing doesn't really\r\n% exist.\r\n%\r\n% <include>tests\/ClassificationWithPersistenceTest.m<\/include>\r\n%\r\n% Note this test class has an additional *|TestTags|* attribute on the\r\n% classdef block. In that attribute you can list some tags that will help\r\n% identify the intended purpose(s) of the test. In this case we can\r\n% identify this test as related to both the |'Classification'| and\r\n% |'Persistence'| features.\r\n%\r\n% This is fun, lets do some more:\r\n%\r\n% <include>tests\/CoreNumericsUnitTest.m<\/include>\r\n%\r\n% Now we have a nice beautiful numerics unit test. How about that system test we talked\r\n% about?\r\n% \r\n% <include>tests\/AcceptanceSystemTest.m<\/include>\r\n%\r\n% This test was a bit different, as you can see the *|TestTags|* attribute\r\n% is not only on the classdef block, but is included on the test\r\n% methods block as well. Well, ultimately these tags apply to test methods,\r\n% but including *|TestTags|* on the classdef block is a sort of shorthand\r\n% for applying the tags to all of the methods of that class (and all\r\n% subclasses if any). The first two test examples clearly wanted these tags\r\n% applied to all methods of the class. However, system testing, in\r\n% particular is a bit more nuanced. System tests can span the full feature\r\n% set of a toolbox, and it is not uncommon for different tests to touch\r\n% different portions of the toolbox functionality. In this case, both test\r\n% methods are |'UI'| but only one of them deals with |'Persistence'| and\r\n% one with |'Numerics'|. Applying the tags at the method level allows us to\r\n% differentiate these two.\r\n%\r\n% Well alright, what does this give us? Test selection anyone? Let's look\r\n% at our full suite containing all these tests:\r\n%\r\nimport matlab.unittest.TestSuite;\r\nfullSuite = TestSuite.fromFolder('tests')\r\n\r\n%%\r\n%\r\n% The careful reader will note that this suite's display actually shows |4\r\n% Unique Tags|. If you are running in MATLAB this is actually a hyperlink\r\n% that shows you the full list of tags contained in the suite. When clicked\r\n% it looks something like:\r\n% \r\n% \r\n%           Tag       \r\n%     ________________\r\n%     'Classification'\r\n%     'Numerics'      \r\n%     'Persistence'   \r\n%     'UI'  \r\n%\r\n%\r\n% Now here's a quick way to see which tests we are working with in a suite.\r\n% It is a concise way to place the names of each suite element into a\r\n% column cell array which displays nicely.\r\n{fullSuite.Name}.'\r\n\r\n%%\r\n%\r\n% Now we can slice and dice this suite however we want based on our tags\r\n% using the nice\r\n% <https:\/\/www.mathworks.com\/help\/matlab\/ref\/matlab.unittest.testsuite.selectif.html\r\n% selectIf> method:\r\n\r\npersistenceSuite = fullSuite.selectIf('Tag','Persistence');\r\n{persistenceSuite.Name}.'\r\n\r\n\r\n%%\r\n% It even supports wildcards:\r\nnumericsSuite = fullSuite.selectIf('Tag','Num*');\r\n{numericsSuite.Name}.'\r\n\r\n%% \r\n% Finally, one of the huge benefits of tagging tests like this is that you\r\n% don't need to  commit to only one axis to categorize your test content.\r\n% This example has shown adding specific tags according to features of the\r\n% toolbox. However, we could also take the type of test as another axis we\r\n% may want to work with. For example, if you are a fan of Google's\r\n% <http:\/\/googletesting.blogspot.com\/2010\/12\/test-sizes.html\r\n% small\/medium\/large> test nomenclature you may want to set up a CI system\r\n% to run small tests for every check-in, medium tests every night, and\r\n% large tests at the end of each iteration. This deferred testing strategy\r\n% becomes very easy with the aid of test tags. Let's add |'Small'|,\r\n% |'Medium'|, and |'Large'| tags.\r\n%\r\n% <include>tests\/v2\/ClassificationWithPersistenceTest.m<\/include>\r\n%\r\n% <include>tests\/v2\/CoreNumericsUnitTest.m<\/include>\r\n% \r\n% <include>tests\/v2\/AcceptanceSystemTest.m<\/include>\r\n%\r\n% We can even prefilter these tests in test suite creation methods like\r\n% fromFolder:\r\n\r\nsmallTests = TestSuite.fromFolder('tests\/v2', 'Tag', 'Small');\r\n{smallTests.Name}.'\r\n\r\nmediumTests = TestSuite.fromFolder('tests\/v2', 'Tag', 'Medium');\r\n{mediumTests.Name}.'\r\n\r\nlargeTests = TestSuite.fromFolder('tests\/v2', 'Tag', 'Large');\r\n{largeTests.Name}.'\r\n\r\n\r\n%%\r\n% A key point here is that while this test suite is very small and\r\n% manageable, this definitely does not hold in any serious software\r\n% development project. Using test tags is a nice way to avoid relying too\r\n% much on limited folder or package structure for test organization,\r\n% instead favoring tagging each test along whichever axes it belongs to.\r\n%\r\n% Then when you are looking for exactly the right set of tests to exercise\r\n% exactly the right pieces of your software product......(wait for it)....\r\n%\r\n% \r\n% \r\n% <<2015TagYoureIt.png>>\r\n% \r\n##### SOURCE END ##### fed0e2aae58b4a89920f579a202ade3e\r\n-->","protected":false},"excerpt":{"rendered":"<div class=\"overview-image\"><img decoding=\"async\"  class=\"img-responsive\" src=\"https:\/\/blogs.mathworks.com\/developer\/files\/2015TagYoureIt.png\" onError=\"this.style.display ='none';\" \/><\/div><p>\r\n\r\nI have found that with any reasonably sized software project, sooner or later organization becomes important. As additional features and capabilities are introduced into a toolbox it becomes... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/developer\/2015\/09\/08\/test-tags\/\">read more >><\/a><\/p>","protected":false},"author":90,"featured_media":0,"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\/249"}],"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=249"}],"version-history":[{"count":10,"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/posts\/249\/revisions"}],"predecessor-version":[{"id":260,"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/posts\/249\/revisions\/260"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/media?parent=249"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/categories?post=249"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/tags?post=249"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}