{"id":7734,"date":"2018-09-04T17:25:09","date_gmt":"2018-09-04T22:25:09","guid":{"rendered":"https:\/\/blogs.mathworks.com\/simulink\/?p=7734"},"modified":"2018-09-04T17:25:09","modified_gmt":"2018-09-04T22:25:09","slug":"continuous-integration-with-simulink-project-and-simulink-test","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/simulink\/2018\/09\/04\/continuous-integration-with-simulink-project-and-simulink-test\/","title":{"rendered":"Continuous Integration with Simulink Project and Simulink Test"},"content":{"rendered":"<p>A few days ago, my colleague Mariano published <a href=\"https:\/\/blogs.mathworks.com\/developer\/2018\/08\/23\/gitlab-jenkins-workflow\/\">a blog post on the Developer Zone<\/a> describing how to run a MATLAB Test suite on a Continuous Integration server every time changes are pushed to a Git repository branch.<\/p>\n<p>As you probably guessed, as soon as I saw that, I had to implement it in a Simulink context. Let's see how that went.<\/p>\n<p><strong>The Big Picture<\/strong><\/p>\n<p>Here is the big picture of the workflow:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/images\/simulink\/2018Q3\/GitJenkinsWorkflow.png\" alt=\"Simulink Project-Git-Jenkins workflow\" \/><\/p>\n<p>The main steps are:<\/p>\n<ul>\n<li>We have a <a title=\"https:\/\/www.mathworks.com\/discovery\/simulink-projects.html (link no longer works)\">Simulink Project<\/a> with source control integration configured to a <a href=\"https:\/\/about.gitlab.com\/\">GitLab<\/a> repository<\/li>\n<li>In the Simulink Project, we have a test suite created using <a href=\"https:\/\/www.mathworks.com\/products\/simulink-test.html\">Simulink Test<\/a><\/li>\n<li>Every time we commit and push changes to a specific branch of the Git repository, the remote repository notifies a <a href=\"https:\/\/jenkins.io\/\">Jenkins<\/a> server<\/li>\n<li>As soon as it gets notified, the Jenkins server pulls the commit, launches MATLAB, opens the Simulink Project and runs the Simulink Test test suite<\/li>\n<li>If the test passes, the Jenkins server creates a merge request in GitLab.<\/li>\n<li>If a test fails, the Simulink Test results are saved and a bug issue in GitLab is created.<\/li>\n<\/ul>\n<p>This last step of saving the Simulink Test session is very important. As you will see below, it allows me to analyze the simulation results locally without re-running the failed test, saving me a lot of time if the simulation I am testing takes a long time to simulate.<\/p>\n<p>Now it's time to go into the details.<\/p>\n<p><strong>Some Background<\/strong><\/p>\n<p>Here is a quick recap of the steps to go through outside the MATLAB environment, in Jenkins and GitLab. See <a href=\"https:\/\/blogs.mathworks.com\/developer\/2018\/08\/23\/gitlab-jenkins-workflow\/\">Mariano's post<\/a> for more details:<\/p>\n<ul>\n<li>In Jenkins, specify the repository URL, the branch to build and my credentials<\/li>\n<li>In Jenkins, set Build Trigger to build when a change is pushed to GitLab<\/li>\n<li>In Jenkins, specify the build command to launch MATLAB and run my tests<\/li>\n<li>In GitLab, setup a Push Event Web hook to the GitLab CI Service URL of Jenkins. This will be triggered every time I will push changes to my testing branch<\/li>\n<p>Now let's move to the fun stuff :-)<\/p>\n<p><strong>Simulink Project<\/strong><\/p>\n<p>For this example, we will reuse the same example we used before in <a href=\"https:\/\/blogs.mathworks.com\/simulink\/2017\/05\/25\/simulation-based-testing-with-simulink-test-manager\/\">this post<\/a> where we tested that the results of a simulation was matching results from a generated executable using Software-In-The-Loop simulation:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/images\/simulink\/2017Q2\/challenge.png\" alt=\"Simulink versus Software in the loop validation\" \/><\/p>\n<p>The post <a href=\"https:\/\/blogs.mathworks.com\/simulink\/2017\/05\/25\/simulation-based-testing-with-simulink-test-manager\">Simulation Based Testing with Simulink Test Manager<\/a> describes in detail how to set up the test, so I will not repeat it here.<\/p>\n<p>What I added for this blog is to create a Simulink Project, adding all the files to it and configure the source control integration.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/images\/simulink\/2018Q3\/GitDetails.png\" alt=\"Source Control Integration in Simulink Project\" \/><\/p>\n<p><strong>Running the Simulink Test test suite on the Jenkins Server<\/strong><\/p>\n<p>In Jenkins, we need to specify a build command. This build command will <a href=\"http:\/\/www.mathworks.com\/help\/matlab\/ref\/matlablinux.html\">launch the MATLAB executable in \"nodisplay\" mode<\/a>  and use the -r flag to run some MATLAB code (See <a href=\"https:\/\/blogs.mathworks.com\/developer\/files\/JenkinsGitlabPost_4-1.png\">this image<\/a>). In my case, the MATLAB code is:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/images\/simulink\/2018Q3\/jenkinsCode.png\" alt=\"Jenkins Build command\" \/><\/p>\n<p>The function <tt>runMyTests<\/tt> is similar to the one presented in Mariano's post. Here is what it looks like:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/images\/simulink\/2018Q3\/runMyTests.png\" alt=\"running the tests\" \/><\/p>\n<p>Things to notice:<\/p>\n<ul>\n<li>The tests are run through the <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/matlab-unit-test-framework.html\">MATLAB Testing Framework<\/a>. Thanks to that, my test suite can include tests created using Simulink Test and using the MATLAB Testing Framework. As they say where I come from: <strong>A test is a test!<\/strong><\/li>\n<li>The functions <tt>writeMergeRequest()<\/tt> and <tt>writeIssue()<\/tt> contain code similar to Mariano's post, using <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/webwrite.html\">webwrite<\/a> to create a merge request or an issue in GitLab <a href=\"https:\/\/docs.gitlab.com\/ee\/api\/\">using its API<\/a>.<\/li>\n<li>I create a folder to store the results in case of failure<\/li>\n<li><a href=\"https:\/\/www.mathworks.com\/help\/sltest\/ref\/sltest.testmanager.exportresults.html\">sltest.testmanager.exportResults<\/a> is used to save the test results in case of a failure.<\/li>\n<\/ul>\n<p><strong>Inspecting Test Failure<\/strong><\/p>\n<p>Depending on how your Jenkins server is configured, you could write MATLAB code to put the test results at any place convenient for you. By default, I can go grab my results file in the Jenkins workspace.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/images\/simulink\/2018Q3\/jenkinsResults.png\" alt=\"Getting the results\" \/><\/p>\n<p>Once I get the results file, I can simply double-click on it in MATLAB and the Test Manager will show what went wrong.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/blogs.mathworks.com\/images\/simulink\/2018Q3\/theFinalResults.png\" alt=\"Visualizing the results\" \/><\/p>\n<p>I will repeat it... since I often deal with simulations that take hours to run, getting the results file from the server saves me a lot of time since I do not need to re-run the simulation on my machine.<\/p>\n<p><strong>Now it's your turn<\/strong><\/p>\n<p>Are you incorporating change management and continuous integration tools like Git and Jenkins in your team-based Model-Based Design projects? If yes, tell us more about your setup in the comments below.<\/p>\n","protected":false},"excerpt":{"rendered":"<div class=\"overview-image\"><img decoding=\"async\"  class=\"img-responsive\" src=\"https:\/\/blogs.mathworks.com\/images\/simulink\/2018Q3\/theFinalResults.png\" onError=\"this.style.display ='none';\" \/><\/div>\n<p>A few days ago, my colleague Mariano published a blog post on the Developer Zone describing how to run a MATLAB Test suite on a Continuous Integration server every time changes are pushed to a Git... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/simulink\/2018\/09\/04\/continuous-integration-with-simulink-project-and-simulink-test\/\">read more >><\/a><\/p>\n","protected":false},"author":41,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[24,545,63],"tags":[538,376,536,497],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/simulink\/wp-json\/wp\/v2\/posts\/7734"}],"collection":[{"href":"https:\/\/blogs.mathworks.com\/simulink\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.mathworks.com\/simulink\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/simulink\/wp-json\/wp\/v2\/users\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/simulink\/wp-json\/wp\/v2\/comments?post=7734"}],"version-history":[{"count":21,"href":"https:\/\/blogs.mathworks.com\/simulink\/wp-json\/wp\/v2\/posts\/7734\/revisions"}],"predecessor-version":[{"id":7933,"href":"https:\/\/blogs.mathworks.com\/simulink\/wp-json\/wp\/v2\/posts\/7734\/revisions\/7933"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/simulink\/wp-json\/wp\/v2\/media?parent=7734"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/simulink\/wp-json\/wp\/v2\/categories?post=7734"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/simulink\/wp-json\/wp\/v2\/tags?post=7734"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}