Testing private functions in classes
    23 visualizaciones (últimos 30 días)
  
       Mostrar comentarios más antiguos
    
    JWTay
      
 el 16 de Oct. de 2017
  
    
    
    
    
    Comentada: Paul Wintz
      
 el 18 de Ag. de 2025
            I'm wondering what the best way is to write unit tests for private functions and properties in classes. Say for example, I have a class that represents a ball launched as a projectile:
class ball
  %
  properties (Access = private)
     initialSpeed = 25;  %m/s
     acceleration = -10;  %m/s^2
  end
  %
  methods 
    function distTravelled = getDistanceTravelled(obj, timeElapsed)
        % Estimate total distance traveled by the ball 
        % (I know this is a bad approximation)
        currSpeed = obj.getCurrSpeed(timeElapsed);
        distTravelled = 0.5 * (obj.initialSpeed + currSpeed) * timeElapsed;
    end
  end
  %
  methods (Access = private)
      function currSpeed = getCurrSpeed(obj, timeElapsed)
         %Calculate current speed of ball
         currSpeed = obj.initialSpeed + obj.acceleration * timeElapsed;
      end
  end
end
How should I write a test to check that the values for acceleration or that the value returned by the method getCurrSpeed is accurate? Should I just allow access to the testing functions?
0 comentarios
Respuesta aceptada
  per isakson
      
      
 el 19 de Oct. de 2017
        
      Editada: per isakson
      
      
 el 20 de Oct. de 2017
  
      First goggle "test private method" and read about why you should not do it (and a few ways to do it).
One way (for handle classes only) is to include the test in the class itself.
>> mc = MyClass
mc = 
  MyClass with no properties.
>> mc.test_private
Private mysort is running
>>
where
classdef    MyClass < matlab.unittest.TestCase
    %
    methods ( Test )
        function test_private( this )
            this.mysort
        end
    end
    methods ( Access = private )
        function  mysort( this )
            fprintf( 'Private mysort is running\n' )
        end
    end   
end
A better workaround based on localfunctions (added 19 hours later)
>> mc = MyClass;
>> fh = mc.get_local_function_handle;
>> fh = fh{1}
fh = 
    @the_tricky_algorithm_
>> fh( mc )
ans =
   144
>>
where in one mfile
classdef    MyClass 
    properties
        val = 12;
    end
    methods 
        function    fh = get_local_function_handle( ~ )
            fh = localfunctions();
        end
    end
    methods ( Access = private )
        function  my_private_method( this )
            fprintf( 'Private mysort is running\n' )
            the_tricky_algorithm_( this )
        end
    end   
end
function    out = the_tricky_algorithm_( this )
    out = this.val .* this.val;
end
3 comentarios
  Walter Roberson
      
      
 el 20 de Oct. de 2017
				When I worked in industry, we tested everything.
Later I worked with some people developing medical devices; I'm pretty sure their applications would have been rejected if they didn't test everything.
Más respuestas (4)
  Wil Koenen
      
 el 3 de Jul. de 2018
        If you're using matlab.unittest.TestCase for your test, but you don't want matlab.unittest.TestCase to be a superclass of the class under test, you can grant access to private functions by providing a list of classes instead of the private keyword. Example:
classdef classUnderTest
    ...
    methods ( Access = { ?classUnderTest, ?matlab.unittest.TestCase } )
        ...
    end   
end
3 comentarios
  Martin Lechner
      
 el 2 de Jun. de 2020
				
      Editada: Martin Lechner
      
 el 2 de Jun. de 2020
  
			This solution works perfect. Thanks.
I enabled explictly my test class but this included my unit test class in the compiler output. Your solution to enable access for all matlab.unittest.TestCase doesn't include the test classes in the compiler output.
  Paul Wintz
      
 el 18 de Ag. de 2025
				
  Sean de Wolski
      
      
 el 19 de Oct. de 2017
        
      Editada: Sean de Wolski
      
      
 el 19 de Oct. de 2017
  
      I would test it through the front door with a known set of inputs and expected outputs. This is the beautiful thing about classes in that you can mask the implementation from the outside world and change it later if necessary.
e.g.:
In Unit Test
b = ball
distTravelled = getDistanceTravelled(b, 20);
testCase.verifyEqual(distTravelled, whatever_is_right_for20);
distTravelled = getDistanceTravelled(b, 200);
testCase.verifyEqual(distTravelled, whatever_is_right_for200);
testCase.verifyError(@()getDistanceTravelled(b, -2), 'ball:NoNegativeTime');
You can use the Code Coverage Plugin for a test runner to make sure that you're exciting all of the lines of the implementation and that should be fine.
  Sanjana Ramakrishnan
    
 el 19 de Oct. de 2017
        
      Editada: per isakson
      
      
 el 19 de Oct. de 2017
  
      Refer the below link for an example of writing MATLAB unit tests relevant to your case:
Please note that testing private functions is just the same as testing any other function in a class.
You can design your own testing strategies as per your requirement.
1 comentario
  per isakson
      
      
 el 19 de Oct. de 2017
				"testing private functions is just the same as testing any other function in a class" Is that really so?
  Tom Hawkins
      
 el 12 de Feb. de 2020
        Would you be happy to define your properties/methods as Protected, rather than Private? If so you could then create a subclass of your class as part of your test suite, for example:
classdef BallWithAccessToProtected < ball
    methods
        function obj = BallWithAccessToProtected(varargin)
            obj@ball(varargin{:})
        end
        function SetProtectedProperty(obj, prop, value)
            obj.(prop) = value;
        end
        function v = GetProtectedProperty(obj, prop)
            v = obj.(prop);
        end
    end
end
This subclass exposes the protected properties via its SetProtectedProperty and GetProtectedProperty methods, for example:
>> b = BallWithAccessToProtected(someArgs);
>> b.GetProtectedProperty('initialSpeed')
ans = 
    25
You can figure out how to extend that to accessing methods if you need to.
Protected means that users of your class's 'official' API can't access those properties and methods, but someone who's willing to subclass it can (as we've done above) - but remember that some languages like Python don't even have a mechanism for restricting access to internal properties and methods of a class, only a naming convention to show which ones you shouldn't really use.
1 comentario
  Wil Koenen
      
 el 13 de Feb. de 2020
				In your example, you could leave out the constructor, because MATLAB supplies a default constructor that does the same (reference).
When a subclass does not define a constructor, the default constructor  passes its inputs to the direct superclass constructor. This behavior is useful when there is no need for a subclass to define a constructor,  but the superclass constructor does require input arguments.
Ver también
Categorías
				Más información sobre Testing Frameworks en Help Center y File Exchange.
			
	Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!








