Search code examples
matlabunit-testingparameterized-unit-test

How to generate method parameters based on class parameters for Matlab unit tests


A program I am working on performs calculations that involve objects that can only have several possible sets of values. These parameter sets are read from a catalogue file.

As an example say the objects are representing cars and the catalogue contains a value set {id: (name, color, power, etc.)} for each model. There are however many of these catalogues.

I use Matlab's unittest package to test if the calculations fail for any of the property combinations listed in the catalogues. I want to use this package, because it provides a nice list of entries that failed. I already have a test that generates a cell array of all ids for a (hardcoded) catalogue file and uses it for parameterized tests.

For now I need to create a new class for each catalogue file. I would like to set the catalogue file name as a class parameter and the entries in it as method parameters (which are generated for all class parameters), but I cannot find a way to pass the current class parameter to the local method for creating the method parameter list.

How can I make this work?

In case it is important: I am using Matlab 2014a, 2015b or 2016a.


Solution

  • I have a couple thoughts.

    1. Short answer is no this can't be done currently because the TestParameters are defined as Constant properties and so can't change across each ClassSetupParameter value.

    2. However, to me creating a separate class for each catalogue doesn't seem like a bad idea. Where does that workflow fallover for you? If desired you can still share code across these files by using a test base class with your content and an abstract property for the catalogue file.

      classdef CatalogueTest < matlab.unittest.TestCase
          properties(Abstract)
              Catalogue;
          end
          properties(Abstract, TestParameter)
               catalogueValue
          end
      
          methods(Static) 
              function cellOfValues = getValuesFor(catalog)
                  % Takes a catalog and returns the values applicable to 
                  % that catalog.
              end
          end
      
          methods(Test)
              function testSomething(testCase, catalogueValue)
                  % do stuff with the catalogue value
              end
              function testAnotherThing(testCase, catalogueValue)
                  % do more stuff with the catalogue value
              end
          end
      
      end
      
      
      
      classdef CarModel1Test < CatalogueTest
      
          properties
              % If the catalog is not needed elsewhere in the test then
              % maybe the Catalogue abstract property is not needed and you
              % only need the abstract TestParameter.
              Catalogue = 'Model1';
          end
          properties(TestParameter)
               % Note call a function that lives next to these tests
               catalogueValue = CatalogueTest.getValuesFor('Model1');
          end
      end
      

      Does that work for what you are trying to do?

    3. When you say method parameters I assume you mean "TestParameters" as opposed to "MethodSetupParameters" correct? If I am reading your question right I am not sure this applies in your case, but I wanted to mention that you can get the data from your ClassSetupParameters/MethodSetupParameters into your test methods by creating another property on your class to hold the values in Test[Method|Class]Setup and then referencing those values inside your Test method. Like so:

      classdef TestMethodUsesSetupParamsTest < matlab.unittest.TestCase
          properties(ClassSetupParameter)
              classParam = {'data'};
          end
          properties
              ThisClassParam
          end
      
          methods(TestClassSetup)
              function storeClassSetupParam(testCase, classParam)
                  testCase.ThisClassParam = classParam;       
              end
          end
      
          methods(Test)
              function testSomethingAgainstClassParam(testCase)
                  testCase.ThisClassParam
              end
          end
      
      end
      

      Of course, in this example you should just use a TestParameter, but there may be some cases where this might be useful. Not sure if its useful here or not.