Writing tests does tend to force the code structure to be a little different. IME this is often to the benefit of the code as it tends to encourage you to break your code up into more modular testable chunks which in turn makes your code more flexible to change in the future. It’s also important to note that you don’t need to test everything!
It’s important to note that a “UnitTest” should test a “unit” which ideally should be well isolated. I would suggest that any dependencies it has should be injected or the object itself should be used to compose other objects which have little to no logic and therefore probably won’t benefit from testing in the same way.
In your case I can see you have an AudioProcessor
with what appears to be a static function called negativeModulo
, given this is a static function this can be removed from your AudioProcessor
and tested completely independently from the processor itself, it really shouldn’t need the processor.
You should be able to separate almost everything from the AudioProcessor itself so that hopefully all the AudioProcessor
does is pull some objects together, report the name, if it supports midi, etc. and these things aren’t normally particularly useful to test.
For example do you really need to test that the name of the processor? if it failed what would it tell you? that you changed the name? well the chances are that’s exactly what you did and therefore exactly what you want. There’s not really any logic that can fail. Tests should be testing behaviour to ensure that you meant for some behaviour to change, if you add new functionality did you mean to change some existing functionality in the process.
A good way to figure out if something is likely worth testing is to think of the following three points
- Given (some state)
- when (I do something)
- Then (I expect this result)
A good way to figure out if your test is useful is to ask yourself what would I do if this ever failed, if the only real answer is change the test so it passes then it’s probably not worth testing.
In general I’m suggesting your AudioProcessor should be a very simple composition of other functions and objects, all of which are testable. This should get the level of coverage you need without over complicating anything.
If you really want to test the processor it’s certainly possible, for example
- You could define the preprocessors definitions in the console app
- You create an audio processor that takes all of the preprocessor definitions as arguments. In your console app pass these explicitly, but in the plugin pass the preprocessor definitions to the AudioProcessor in your
createPluginFilter()
function
Also if you do want to go this route I don’t think there should be any need for juce_audio_plugin_client
as the AudioProcessor class is defined in the juce_audio_processors
module. If I’m not mistaken your plugin shouldn’t depend on anything in that module.
It’s also worth noting that you can always setup tests using tools like pluginval
for testing the plugin as a whole.
I hope that helps.