Testing out projects a bit more

So now you know a bit about projects . You can see how they enable you to create a standard environmental setup so that you (and others!) can reproduce the right conditions to get going without fuss or learning curves. It gives you a fundamental unit of development so that all contributors know how to immediately get going and contribute to your work.

For kicks, I wanted to show how projects can begin to improve the workflow for a real example project that is out there, show how projects can be used for existing code, and maybe while we're at it we can get into a few more of the benefits projects have to offer.

So with that, let me introduce libDirectional! What does it do? I actually have very little clue. It is a library related to "directional statistics as well as recursive estimation on directional manifolds", a topic which to be honest I know very little about. However, it looks like a project that is quite well put together. It has good documentation, a nice consistent way to build its mex files and other artifacts derived from the source code, it provides and manages its dependencies, and it has a great comprehensive test suite. Kudos libDirectional!

I think that projects can help take it to the next level! This project is already in git, so let's go ahead and just turn it into a project by creating a new project from git:

You will then be prompted for the repository:

and to confirm the name of the project:

As Laura showed you last time, you can leverage projects to ensure that the right paths are added inherently to the project on startup. Installation instructions are no longer needed, a new contributor can simply load the project. This also means that the startup file, which essentially handles path management, isn't needed anymore.

[pathstr,~,~] = fileparts(mfilename('fullpath'));
clearvars pathstr



The project setup guides you through this, and we can now go ahead and remove the startup file which isn't needed anymore:

Note that once the project is setup you can easily turn this into a toolbox to distribute to users of the project who just want to use it, and don't really need to contribute to it, but I'll leave that for you to explore as an exercise.

So now a contributor can get up and running simply by cloning the git repository and launching the project. Done. No instructions needed. A user can get up and running simply by installing the toolbox as an add on. Lovely.

But wait there's more! There is also a relatively simple, yet powerful capability built into projects that is worth highlighting, and which starts to kick us off into additional workflows, such as ensuring quality through continuous integration.

The key is this -- projects know how to test themselves. Or perhaps they enable the project author to encode precisely how to test the project so that other people (such as colleagues) and computers (such as CI build agents) can simply ask, "Project, test yourself!" and it is off to the races. This is done simply by adding "Test" labels as metadata to the test files, and then, well, that's it!

In fact, you may not even need to add a Test label, since the project makes a solid effort at identifying what is a test and adding the label for you. However, it may not do this for all tests, such as script-based tests or tests that inherit from subclasses of matlab.unittest.TestCase, so be sure to confirm all your tests are labeled appropriately. In this case, projects do a nice job of labeling them all appropriately by default. If you want to exclude some tests from your "standard" project test suite you can do this by removing the label as shown below. This might come in handy in some situations, such as when some of your tests take a long time to execute and you only want to run them in special deferred test runs.

Now with your tests labeled appropriately with project metadata, you can actually create a test suite directly from the project and run it. It's as easy as navigating to the project root and calling runtests. Equivalently, you can simply pass the root folder of the project to the runtests function:

runtests libDirectional

Setting up ProjectFixture
Done setting up ProjectFixture: Opened project 'libDirectional'.
__________

Running TessellateS3Test
.
Done TessellateS3Test
__________

Running AbstractCircularDistributionTest
.....
Done AbstractCircularDistributionTest
__________

... (SNIP) ...

Tearing down ProjectFixture
Done tearing down ProjectFixture: Closed project 'libDirectional'.
__________



Note in the output above, that this leverages a ProjectFixture. This is key, because the ProjectFixture loads the project, thus ensuring the development environment is set up properly with the correct path and other requirements before running the tests.

You can also customize your test runner with various plugins. In this case you can use the testsuite function to (similarly) create the tests for the project (complete with the ProjectFixture attached), and then create and tune the runner you'd like to use for these tests to your hearts content so you can do things like produce TAP or JUnit style test artifacts, PDF or html reports, coverage, Simulink Test customizations and many many other things you may want to do.

All you need to do now to set up your project for testing in CI is simply a git clone, followed by a matlab -batch assertSuccess(runtests) from the project root (which likely is the root of the git repo you just cloned). Done. Easy peasy. Let's keep you worrying about things other than your CI and development setup. You know, really hard and important things, like "directional statistics as well as recursive estimation on directional manifolds".