{"id":1474,"date":"2018-03-22T14:07:37","date_gmt":"2018-03-22T18:07:37","guid":{"rendered":"https:\/\/blogs.mathworks.com\/developer\/?p=1474"},"modified":"2018-03-22T14:14:46","modified_gmt":"2018-03-22T18:14:46","slug":"live-function-based-tests-as-executable-specifications","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/developer\/2018\/03\/22\/live-function-based-tests-as-executable-specifications\/","title":{"rendered":"Flex your Specs"},"content":{"rendered":"<p>Wow folks, its been a long time! I feel like I am an old friend returning from traveling on a long epic adventure. Just call me Bilbo, although sadly I would make for a very poor hobbit given I am about as tall as Kobe Bryant and am missing the trademark foot hair. Anyway, my apologizes for the long absence from posting. The good news, however, is that I feel like I am returning from my adventures with many great and wonderful stories to tell! Many of these stories will be related to the specific epic adventure that is the new <a href=\"https:\/\/www.mathworks.com\/products\/new_products\/latest_features.html\">R2018a release of MATLAB<\/a>. Check out the <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/release-notes.html\">release notes<\/a>, it's a beast! There were huge updates to the live coding ecosystem, like live functions, a new intuitive method for debugging live code, and adding interactive controls to your code! Super exciting. <\/p>\r\n      <p>What kind of fun things can we do with this? Well, first why don't we apply this feature to our own development approach and use it to write our tests? Do you remember way back when the test framework was still new? The second release of the test framework (R2013b) introduced the notion of function based testing, and I <a href=\"https:\/\/blogs.mathworks.com\/loren\/2013\/10\/15\/function-is-as-functiontests\/\">blogged about it<\/a> on Loren's blog. We talked through at that time how we can leverage testing to ensure our <em>engineering<\/em> designs stay up to snuff in the face of a changing environment, new requirements, and code updates. I made the case that the tests become the specification, and since they are executable and can be run against all changes we know that the specification is always up to date. <\/p>\r\n      <p>This is certainly as true now as it was then, but live functions are a game changer. Why is that? Well, even though the tests act as an executable specification, most of the time we still need another form of the specification that is more readable and can be shared without getting into the nitty gritty of the code. What invariably happens then is that we end up having two specifications, the first to communicate the intent of the software, and the other to lock down that intent. Here we get to <a href=\"https:\/\/en.wikipedia.org\/wiki\/Segal%27s_law\">Segal's law<\/a>, which states <\/p>\r\n      <p><b><em><center>A man with a watch knows what time it is. A man with two watches is never sure.<\/center><\/em><\/b><\/p>\r\n      <p>With a test and a spec, we put ourselves in the unenviable position of having two truths. We always know that the tests keep the software and the test aligned, otherwise we fail tests and are quickly (hopefully) notified. But if someone changes the spec but forgets to update the test there is no such notification. Behavior Driven Development (<a href=\"https:\/\/en.wikipedia.org\/wiki\/Behavior-driven_development\">BDD<\/a>) evolved to try to address this by structuring the test directly in specification form and using BDD frameworks to update the spec directly from the test in a new readable format, but personally I have always found that the hoops you need to jump through with these frameworks prevent this dream from becoming a reality. <\/p>\r\n      <p>Well now that reality is here and it is called live functions! With live functions you don't need any BDD framework. The code can still look like code. It's not a big deal if test method names don't <b> <inline style=\"font-family: monospace, monospace; font-size: inherit;\">perfectly_describe_the_scenario_with_underscores_between_words_which_by_the_way_starts_to_get_really_long_in_real_world_cases(testCase)<\/inline><\/b>. Instead, the function can be written with the kind of rich text, equations, and images that scientific and engineering disciplines need in their specifications without impacting how the code is written, yet is still in the same document as the code. <\/p>\r\n      <p>Getting back to <a href=\"https:\/\/blogs.mathworks.com\/loren\/2013\/10\/15\/function-is-as-functiontests\/\">that blog post<\/a>, it uses the standard Mass-Spring-Damper example that is just so fun to play with. When we write that test as a live function we can put all of the specification directly in the document. In fact, this blog post itself is a live function, and below we turn it into an executable specification when we make it a live function-based test. Let's see it in action. <\/p>\r\n      <h3>The Spec (you know, Test)<\/h3>\r\n      <p>The system we are designing is a classic mass spring damper system with the following model:<\/p>\r\n      <p><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/developer\/files\/testMassSpringDamper_1-2.png\"><\/p>\r\n      <p>Where:<\/p>\r\n      <p><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/developer\/files\/testMassSpringDamper_2-2.png\"><\/p>\r\n      <p><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/developer\/files\/testMassSpringDamper_3-2.png\"><\/p>\r\n      <p><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/developer\/files\/testMassSpringDamper_4-2.png\"><\/p>\r\n      <p><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/developer\/files\/testMassSpringDamper_5-2.png\"><\/p>\r\n      <p>Assuming there are no external forces, the equation of motion for this system is the solution to the second order differential equatio: <\/p>\r\n      <p><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/developer\/files\/testMassSpringDamper_6-2.png\"><\/p>\r\n      <p>What behavior of our system is needed? We define it below as our test. Our main function simply uses the test interface to begin. <\/p><pre class=\"matlab-code\" id=\"matlabcode\" style=\"background-color: #F7F7F7;font-family: monospace;font-weight:normal;border-style: solid; border-width: 1px ;border-color:#E9E9E9;padding-top:5px;padding-bottom:5px;line-height:150%;\"><span style=\"color:rgb(0, 0, 255);\">function<\/span> tests = testMassSpringDamper\r\ntests = functiontests(localfunctions);\r\n<span style=\"color:rgb(0, 0, 255);\">end<\/span>\r\n<\/pre><p>Now we can actually define all of the requirements met by our design and lock it down with the code in the same place.<\/p>\r\n      <h3>Requirement 1: Settling Time<\/h3>\r\n      <p>The 2% settling time of the system should be at or within 2 seconds.<\/p>\r\n      <p><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/developer\/files\/testMassSpringDamper_7-2.png\"><\/p>\r\n      <p><em>Image Credit (<\/em><a href=\"https:\/\/en.wikipedia.org\/wiki\/Step_response#\/media\/File:High_accuracy_settling_time_measurements_figure_1.png\"><em>wikipedia<\/em><\/a><em>)<\/em><\/p>\r\n      <p><b>Boom! <\/b>Here is the lockdown: <\/p><pre class=\"matlab-code\" id=\"matlabcode\" style=\"background-color: #F7F7F7;font-family: monospace;font-weight:normal;border-style: solid; border-width: 1px ;border-color:#E9E9E9;padding-top:5px;padding-bottom:5px;line-height:150%;\"><span style=\"color:rgb(0, 0, 255);\">function<\/span> testSettlingTimeRequirements(testCase)\r\n<span style=\"color:rgb(34, 139, 34);\">% Test that the system settles to within 0.002 of zero under 2 seconds.<\/span>\r\n[position, time] = simulateSystem(springMassDamperDesign); \r\npositionAfterSettling = position(time &gt; 2);\r\nverifyLessThan(testCase, abs(positionAfterSettling), 0.002);\r\n<span style=\"color:rgb(0, 0, 255);\">end<\/span>\r\n<\/pre><h3>Requirement 2: Overshoot<\/h3>\r\n      <p>The percent overshoot should be under 10% as governed by the equation <img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/developer\/files\/testMassSpringDamper_8-2.png\"><\/p>\r\n      <p><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/developer\/files\/testMassSpringDamper_9-2.png\"><\/p>\r\n      <p><em>Image Credit (<\/em><a href=\"https:\/\/upload.wikimedia.org\/wikipedia\/commons\/a\/a4\/Gueteforderungen_SollwertfolgeDynamik.png\"><em>wikipedia<\/em><\/a><em>)<\/em><\/p>\r\n      <p><em><\/em><\/p><pre class=\"matlab-code\" id=\"matlabcode\" style=\"background-color: #F7F7F7;font-family: monospace;font-weight:normal;border-style: solid; border-width: 1px ;border-color:#E9E9E9;padding-top:5px;padding-bottom:5px;line-height:150%;\"><span style=\"color:rgb(0, 0, 255);\">function<\/span> testOvershootRequirements(testCase)\r\n<span style=\"color:rgb(34, 139, 34);\">% Test to ensure that overshoot is less than 0.01<\/span>\r\nposition = simulateSystem(springMassDamperDesign);\r\novershoot = max(position);\r\nverifyLessThan(testCase, overshoot, 0.01);\r\n<span style=\"color:rgb(0, 0, 255);\">end<\/span>\r\n<\/pre><h3>Mic Drop<\/h3>\r\n      <p>There we go. The code and the spec are in one place. Unlike other approaches though, neither the richness of description nor the preferred coding approach end up compromised. The code looks like standard test code. The description of the requirements and the features under test can still benefit from the richness that the live code allows. Ladies and gentlemen, I think we've found a unicorn! The live function (in other words, this blog post) is runnable just like any other test, see: <\/p>\r\n<pre>>> table(runtests('testMassSpringDamper'))\r\nRunning testMassSpringDamper\r\n..\r\nDone testMassSpringDamper\r\n__________\r\n\r\nans =\r\n  2\u00d76 table\r\n                           Name                            Passed    Failed    Incomplete    Duration       Details   \r\n    ___________________________________________________    ______    ______    __________    _________    ____________\r\n    'testMassSpringDamper\/testSettlingTimeRequirements'    true      false       false       0.0042491    [1\u00d71 struct]\r\n    'testMassSpringDamper\/testOvershootRequirements'       true      false       false       0.0038952    [1\u00d71 struct]<\/pre>\r\n\r\n\r\n\r\n      <p>Do you see yourselve benefitting from combining your test and spec into a single runnable live function based test? I'd love to hear about it! <\/p>\r\n      <p>More to come (and sooner, I promise)! Readers of this blog will know that I am particularly partial to the <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/release-notes.html?rntext=&amp;startrelease=R2018a&amp;endrelease=R2018a&amp;category=advanced-software-development&amp;groupby=release&amp;sortby=descending&amp;searchHighlight=\">advanced software development<\/a> category. One quick gander makes it pretty obvious there is a lot more to talk about. I am pretty excited to jump into some app development workflows for example (speaking of unicorns). See you next time. <\/p>","protected":false},"excerpt":{"rendered":"<div class=\"overview-image\"><img decoding=\"async\"  class=\"img-responsive\" src=\"https:\/\/blogs.mathworks.com\/developer\/files\/testMassSpringDamper_9-2.png\" onError=\"this.style.display ='none';\" \/><\/div><p>Wow folks, its been a long time! I feel like I am an old friend returning from traveling on a long epic adventure. Just call me Bilbo, although sadly I would make for a very poor hobbit given I am... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/developer\/2018\/03\/22\/live-function-based-tests-as-executable-specifications\/\">read more >><\/a><\/p>","protected":false},"author":90,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[24,7],"tags":[],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/posts\/1474"}],"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=1474"}],"version-history":[{"count":5,"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/posts\/1474\/revisions"}],"predecessor-version":[{"id":1484,"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/posts\/1474\/revisions\/1484"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/media?parent=1474"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/categories?post=1474"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/tags?post=1474"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}