Public static functions are global functions, in OOP, global anything is bad other than the application singleton. It would create multiple entry points to your code, expanding the global interface, which makes it hard to manage.
This is one of those cases where the framing of the argument matters. A non-complex static function cannot operate in isolations and only functions in the confides it was intended to be used, thus limiting the scope of the "global" to be no more than specific designated use cases.
In a decoupled architecture, a global function that reaches across bundles adds an additional dependency. In OOP, and Symfony specifically, we can use DependencyInjection to handle the loose coupling of our dependencies. Public static functions ignore all of that.
If the helper method is tightly coupled to the dependency logic being used and package management tools are used to insure that the external dependency that's already being referenced is present, then this is a not a real concern.
Fear of duplicate code is often driven by academic knowledge, not real-world experience. In large complex applications, some small amount of duplication for the sake of code soverienty should be acceptable.
Overly dogmatic approaches to 100% test coverage and testing all executed lines of code can lead to brittle tests that don't inform you of anything valuable outside of the fact that your test itself is broken. This can lead to developers not taking tests seriously.
If the "global function" is defined in a specific bundle and only relates to the operations of that bundle, which is versioned separately as a dependency then there is no violation of the loose coupling of dependencies, since the DI to be used wouldn't be present otherwise.
Dependency configuration structure may require knowledge that a loose coupling is not fully aware of. This means that we spend more engineering cycles maintaining standard structures that could just as easily be maintained centrally and merely utilized by the loosely coupled bundles.
The most common unit tests only test the code executed within their scope. When testing code used in other class methods you typically mock the object and its responses to simulate the results and reduce external variables.
You are not testing what arguments are sent to it - what if our code is sending the wrong ones? ie the wrong string. The only way to test that, is to test the outputs and actions it has on your own function.
The only cases in which the test will fail are when the outside code is updated and the expectations in the test were not. This results in test failures that don't actually indicate that anything is wrong and wastes engineering time to update and maintain.
Failure to follow this principle leads to wasted time refactoring brittle tests and reduced trust that the failure should be investigated as an actual issue in the code instead of an issue in the unit test itself.