Access to non-public class members

23 views (last 30 days)
tom
tom on 9 Feb 2024
Edited: tom on 13 Feb 2024
Hello,
I'm currently writing unittests for a code-base which I'm not supposed to change (and honestly don't want to change). To say it nicely, its not written very testable. However I managed to test at least some parts of it. To increase the test coverage and to test things more defensively,
I would like to access non-public class members, such as private methods and properties.
As expected the following statement fails:
myInstance.privateMethod
% yields -> Cannot access method 'privateMethod' in class 'CustomersAwesomeClass'.
What I would like to see working is something like this:
% imaginary code, (similar to the invoke function for COM interfaces)
invoke(myInstance, "privateMethod", arg1 ...)
After spending a day trying various hacks, I'm about to give it up. Isn't it possible to achieve it somehow?
In other programming languages there are direct and indirect mechanisms like Reflection, Metaprogramming, Extensions methods, Friends, Function pointers, Runtime patching and others to achieve it. In MATLAB it seems none of these solution are doable and I don't understand why this is the case.
In my oppinion, access modifiers are supposed to prevent a wrong usage of an interface, but it should not prevent you from invoking code, because there might always be a usecase for that. This is also why there are many languages out there without access modifiers at all...
Anyway, if someone knows a workaround, then please share it with me! Other than that it would also be a solution to get a definitive answer that this is not doable, so that I stop wasting time on this. And if so, maybe Mathworks considers to introduce a backdoor here in the future then...
Any help is appreciated. Thanks

Accepted Answer

Matt J
Matt J on 11 Feb 2024
Edited: Matt J on 11 Feb 2024
You could move the classdef to an @-folder, either manually or programmatically and either temporarily or permanently. Then, add invoke() as a method of the class in a separate mfile, so the folder looks like:
@CustomersAwesomeClass/CustomersAwesomeClass.m
@CustomersAwesomeClass/invoke.m
Now that invoke() has been made a method of the class, it will have access to private methods and properties. However, because this involves no editing of the classdef file CustomersAwesomeClass.m you can tell the customer that your test was non-invasive.
  2 Comments
tom
tom on 12 Feb 2024
Hello Matt,
this is actually a good idea. I think I could use this approach. It is not an ideal solution, but with delegating invoke method/s during the test setup and removing them during the teardown I should be able to write meaningful tests without changing the clients code-base.
(And of course I'm aware that I'm violating a couple of best practices, but for testing this difficult code-base I break some rules anyway... As long as the client is happy, I am happy ;) )
Thank you
Matt J
Matt J on 12 Feb 2024
I'm glad, but if it ends up working for you, please Accept-click the answer.

Sign in to comment.

More Answers (2)

Tijana Röhrer
Tijana Röhrer on 12 Feb 2024
Hi Tom,
one possibility to test private methods is to allow access to the testing framework. In the definition of the method, instead of setting it's access permissions to "private" directly, you would set them as
methods (Access = ?matlab.unittest.TestCase)
This sets the access to private, but additionally allows access to any subclass of matlab.unittest.TestCase, and therefore any test class. If you use other testing frameworks, you would have to use the appropriate superclass such as matlab.uitest.TestCase etc.
This would require a minor modification to your code, but it might be worthwhile.
Best,
Tijana
  1 Comment
tom
tom on 13 Feb 2024
Edited: tom on 13 Feb 2024
Hello Tijana,
thank you, this is also great solution. I think it is probally even better. I must say it looks weird, but its indeed an acceptable minimal change.
Wouldn't it make sense that this is the default behavior for private? In C#, I have seen many developers just making functions public for better testing to prevent the usage of reflection. Especially if you develop test-driven. I know the argumentation is often that you don't need to directly test private members because you only assume modification over a public interface, but sometimes it helps you in writing better tests and it makes assertions of internal states easier. Anyway, Thanks :)

Sign in to comment.


Walter Roberson
Walter Roberson on 9 Feb 2024
Edited: Walter Roberson on 11 Feb 2024
In my oppinion, access modifiers are supposed to prevent a wrong usage of an interface, but it should not prevent you from invoking code, because there might always be a usecase for that.
External access to a non-public property is a "wrong usage of an interface" and MATLAB blocks that access.
It is an access contract: the class is written under the assumption that only the contracted operations can happen, and MATLAB enforces that indeed only the contracted operations can happen.
If there are backdoors possibilities then classes need to be written to protect against the backdoors, by using techniques such as checking the call stack to verify that the call is legitimate.
Consider a class that is acting like a bank account, with defined deposit and withdrawl methods. You do not want there to be a backdoor that permits you to withdraw without a trace.
I suspect that what you are looking for is something like the facility for mocking; https://www.mathworks.com/help/matlab/mocking-framework.html
  5 Comments
Walter Roberson
Walter Roberson on 12 Feb 2024
And having a more liberal opinion about it, can still yield in highly secure software.
No, you cannot.
If you allow backdoors then you have to write the methods to protect against the possibility that this invocation used a backdoor.
tom
tom on 12 Feb 2024
Edited: tom on 12 Feb 2024
Again access modifiers are not a security feature. I assume, that you find more "highly secure software" written in C++ than in Matlab. You even build C++ apps out of Matlab/Simulink most of the time. So all that so-secure code, is converted in C++ anyways. And if you can do it in C++, you cannot claim that this follows any purpose of security. C does not even know the concept of access modifiers, and so many critical systems still run with C nowadays.

Sign in to comment.

Categories

Find more on Programming Utilities in Help Center and File Exchange

Products


Release

R2021b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!