Unit Testing Group

cancel
Showing results for 
Search instead for 
Did you mean: 

Private classes in a library - make them community?

Throughout both this community and the wider available literature, there is a (strong) suggestion that we should only test through a public interface.

For VIs, although sometimes inconvenient, this makes sense.

 

Do people have the same opinions regarding a class marked as private within a library?

 

The idea here being that the class is only used inside the library, so it doesn't need to be publicly accessible. However, if I mark it private, either my tests must be inside the library (and they can't be easily removed at build time, as far as I know, without breaking the library?) or I must not directly test this class.

 

Classes can reasonably be larger than VIs (go figure...) and the argument "you should consider refactoring it into a class and making it part of the new public API" also doesn't desperately help.

 

Are there disadvantages in terms of dependencies when building packages if I make the class in question Community scope, then make my test class (VI Tester based) a friend of the library?

I'm not sure what happens to this static list when I build a package - although the friend doesn't need to be present, I guess it's still listed... Is this considered OK?


GCentral
0 Kudos
Message 1 of 11
(5,731 Views)

Nate had some suggestions in his presentation, which include the community scope, at https://forums.ni.com/t5/Unit-Testing-Group/Unit-Testing-in-LabVIEW/gpm-p/3762773

 

Personally, I am in the camp of testing only the public API. If a class is private, there might be public functions wrapping it and testing those public functions would take care of testing the functionality from the private class.

 

If there are specific functions within a private class that you want to test as public, consider creating a shared library/class that is public and testing that. Then your private class can call those functions.

 

Let's say I have an algorithm that orders an array of songs in a playlist. This might be used within a private class, but the sorting algorithm itself might be used by other classes/libraries. I can make the algorithm public and part of a shared library/class and have my private "HandlePlaylistItems.lvclass" call that public VI.

 

 

For an opportunity to learn from experienced developers / entrepeneurs (Steve, Joerg, and Brian amongst them):
Check out DSH Pragmatic Software Development Workshop!

DQMH Lead Architect * DQMH Trusted Advisor * Certified LabVIEW Architect * Certified LabVIEW Embedded Developer * Certified Professional Instructor * LabVIEW Champion * Code Janitor

Have you been nice to future you?
Message 2 of 11
(5,722 Views)

@FabiolaDelaCueva  escreveu:

 

If there are specific functions within a private class that you want to test as public, consider creating a shared library/class that is public and testing that. Then your private class can call those functions.

 


Hello Fabiola,

 

Just a newbie question in UT. Does this private VIs assumption extends to protected VIs that are going to use/extend parent functions?

 

Regards,

Felipe Pinheiro Silva


Follow my blog for LV content!

0 Kudos
Message 3 of 11
(5,034 Views)

If you test behaviour and not implementation (this is what you should be doing), then you should be able to get away with just testing the public API.

 

If you have some protected vis that are intended to be overridden (such as a template method) and you want to make sure that they are called at the correct time. you might look at Mock Objects. Since it inherits from the class you are testing/its interface then you could call the protected methods and verify that they were called.

 

Here is an example of how to do Mocks in LabVIEW:

 https://gitlab.com/sas_public/class_refactoring_tools

 

I've done some testing on it, but I don't think I have tested calling protected methods. If you find any bugs let me know and I will fix them.

Sam Taggart
CLA, CPI, CTD, LabVIEW Champion
DQMH Trusted Advisor
Read about my thoughts on Software Development at sasworkshops.com/blog
GCentral
0 Kudos
Message 4 of 11
(5,023 Views)

@Taggart  escreveu:

 


Thanks for answer Sam.

 

I'll take a look at the repository and let you know my thoughts.

 

Regards,

Felipe Pinheiro Silva


Follow my blog for LV content!

0 Kudos
Message 5 of 11
(4,999 Views)

@felipe.foz wrote:

@FabiolaDelaCueva  escreveu:

 

If there are specific functions within a private class that you want to test as public, consider creating a shared library/class that is public and testing that. Then your private class can call those functions.

 


Hello Fabiola,

 

Just a newbie question in UT. Does this private VIs assumption extends to protected VIs that are going to use/extend parent functions?

 

Regards,


Hi Felipe,

 

Yes, I assume that the only thing to test is the public API. Protected, private, and community scope methods in a class/library don't need to be tested. If you need to test them, then evaluate if they belong in a shared library/class.

 

Regards,

Fab

For an opportunity to learn from experienced developers / entrepeneurs (Steve, Joerg, and Brian amongst them):
Check out DSH Pragmatic Software Development Workshop!

DQMH Lead Architect * DQMH Trusted Advisor * Certified LabVIEW Architect * Certified LabVIEW Embedded Developer * Certified Professional Instructor * LabVIEW Champion * Code Janitor

Have you been nice to future you?
0 Kudos
Message 6 of 11
(4,985 Views)

Dear Fabiola,

 

in case when we test just public API just, won't it be a problem then to identify source of failures? I mean, if for example some public API VI contains 3 protected VIs in some chain; and test for this public API VI fails - how to identify what is really wrong? Because: each of 3 protected VIs could have failure, and "chaining" logic also could have failures.

0 Kudos
Message 7 of 11
(4,970 Views)

I can't speak for Fab but in my experience - at this point, you are still working on such a small piece of code that debugging is trivial.

 

It is worth stating the reason behind this approach.

 

The public API's tend to be quite stable. They are related to the object's identity, not it's implementation. And they are used in different places in your code so extra thought has probably gone into creating a design that doesn't expect to change much.

 

Testing private methods, in particular, tends to be much more brittle (likely to break/fail) as those APIs tend to be based on the implementation and so you want to change them freely as you refactor.

 

I guess protected methods are a little more stable. If it is more complex you can use mock objects to prove out the "chaining" logic separately. I would still aim to keep the other methods protected if that makes the most sense for the design and stick to testing public. But there may be cases where the ROI is high enough to consider changing the design. Most times, in this case, I do as Fab says and pull out a separate class to be tested.

James Mc
========
CLA and cRIO Fanatic
My writings on LabVIEW Development are at devs.wiresmithtech.com
Message 8 of 11
(4,955 Views)

@kosist90 wrote:

in case when we test just public API just, won't it be a problem then to identify source of failures? I mean, if for example some public API VI contains 3 protected VIs in some chain; and test for this public API VI fails - how to identify what is really wrong? Because: each of 3 protected VIs could have failure, and "chaining" logic also could have failures.


I also had/somewhat still have the same concerns, but after thinking about this more and more I feel like probably this can be symptomatic of a public method that does too much (violations of SRP, if you like).

 

This question originally started for more or less the same question you have here, but on a class rather than VI level.

 

Often(ish) I find that the interface I want to expose doesn't do very much, and I'd like to hide as much implementation as possible from my users (still me, but whatever...).

Then I create a bunch of private VIs, or in this question's case classes, and have these do the "work". I was initially resistant to the idea of making these "workhorse" classes public (perhaps in separate libraries, etc) because I didn't have other use cases for them - they really were only for this specific library (this is still pretty much true for the library this question was about).

However, now I wonder if some refactoring (as described by Fab in her first response regarding song ordering) might allow more generic code to be written that could be used by my library. Even if I don't use it again, I can say that it became more "testable". If I do find a use in the future, I have a pre-tested library to work with.

 

I've grown to quite like the Template method for my interfaces (abstract-ish classes, perhaps now real interfaces?). When reading the comments about protected classes, I wondered if this might suggest a need to test the protected methods, but on closer inspection I still think you only need the public methods (with Template method, these are public static dispatch in LabVIEW, calling protected dynamic dispatch VIs).

Suppose I have a Disk Logging class, which does nothing but has "Open File", "Close File", "Read Data" and "Write Data" (where 'Data' is either a class, or an array of doubles, or a string, or whatever).

If I put additional functionality into the 'abstract-ish' parent class for the Open File to allow e.g. renaming the file when it would overwrite, or timestamping etc, then I can test that probably without a concrete child (depending on my implementation, perhaps).

If I want to do Write/Read pair tests (often argued to be an Integration rather than Unit test, but anyway) then I probably need a concrete child - if I'm testing a specific child's Protected methods, then I can use that child and check the behaviour. If instead I'm more interested in the parent class bits around the Protected method, I can use a mock (maybe keep the data in memory, and then examine what was 'written' without ever needing to write anything to disk using extra public methods that are specific to the testing child class).

 

This necessarily limits my testing of specific children - they might not have the extra code from the parent class necessary to correctly parse or format my input or outputs, but that's fine - because I'll only ever use the children through the public parent class static dispatch methods.

 

Of course, this also creates more methods - so if you don't need the template method and other bits around it, I'd say just use public dynamic dispatch. I don't particularly like the "must call parent" option though - must I call it first, or after, or does it not matter? This can be important, but if so, the best you can do is write it in the VI description. Template method can at least partially avoid this - but if you have grandchildren, you're potentially back to nested layers of functionality and ordering of call parent mattering. Perhaps this is why some authors suggest not inheriting from concrete classes.


GCentral
Message 9 of 11
(4,923 Views)

Thank you cbutcher and James for your answers.

Now it perfectly makes sense to me, especially in case of template/channeling pattern. I use template pattern heavily, in order to implement dynamic dispatch VIs which receive data "from the outside", and not from the class directly - so one could easily see which inputs/outputs should be used, and then caller of such VI passes data in/out - and it is enough to test just this caller, b/c in most of cases it does not contain additional complicated logic.

At the first sight the idea to put some of private VIs (which would be nice to test) into shared library was not clear for me, but now I see the point, and will apply such approach definitely.

Message 10 of 11
(4,908 Views)