4 ms·
I wish that my programming languages had a "public for testing only" scope. Despite the rigorous arguments of the Properly Factor Your Public API crew, I still
by mplewis 3y ago
I wish that my programming languages had a "public for testing only" scope. Despite the rigorous arguments of the Properly Factor Your Public API crew, I still find myself in real-world situations with functions that should not reasonably be used outside of the module, but that I still find valuable to cover with unit tests.
- wavemode 3y agoC++ has "friend" classes, a quirky feature I've never seen in another language. But which solves this very problem.
- sanderjd 3y agoIt's not much different that package-private (the default visibility in java).
- brabel 3y agoWe use package-private and @VisibleForTesting (I forget which library provides that now) for these cases.
- sanderjd 3y ago@VisibleForTesting is mostly documentation; you can just as easily use package private without an annotation. (Though yeah, I think it's good to use the annotation anyway.)
- mvdtnz 3y agoThis exists (in kind of a hacky way) in C# with the ExternalsVisibleTo attribute. It exposes methods and classes only to specified assemblies (like your unit test assemblies). https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.internalsvisibletoattribute?view=net-7.0 https://learn.microsoft.com/en-us/dotnet/api/system.runtime....
- no_butterscotch 3y agoThis exists in many Java based languages, an annotation above a method: @VisibleForTesting or some such.
- gregoryl 3y agoYou can actually stick this in your csproj. I'm on a phone, so bear with me, but roughly <InternalsVisibleTo Include="assemblyname" /> Which means you can do stuff with msbuild props, like auto including a `$(assemblyname).Tests` into your projects.
- zem 3y agoyeah, that one stood out to me too. i would be tempted to make the stronger statement that it is always strictly better to have your private code unit tested, and it is only the limitations of languages and test frameworks that make people reach for ways to test them through the public API.
- pvorb 3y agoBut on the other hand: if it's worthwhile testing your private methods, shouldn't they maybe be refactored to a public/package-private scope, so they can be reused? If you disagree, maybe an illustrative example would help. I couldn't think of one where I want to test a private method in detail that is not worth exposing.
- fiddlerwoaroof 3y agoA lot of the time _private_ methods on one class end up making more sense as public methods on a helper class of some kind (or public methods on other classes). One issue that leads to private methods in Java is the lack of any way to extend the set of operations on built-in classes: a problem that Kotlin and C# solve with extension methods.
- kaba0 3y agoExtension methods are basically just static methods in a helper class that takes the to be extended class as their first argument, and a bit of syntactic sugar on top. That is absolutely imitable in Java.
- fiddlerwoaroof 3y agoYou can imitate it in Java, but the ergonomics are worse.
- jandrewrogers 3y agoA common case for this is very simple APIs with very complex internals that e.g. dynamically switch behaviors or algorithms in certain contexts. The only way to test all the major code paths through the simple API is to hardcode implementation detail into your unit tests to induce all the various switching contexts indirectly. It makes unit tests quite brittle. At the same time, these internals are definitely not public APIs and unusable as such.
- MikeTheRocker 3y agoKotlin has the internal access modifier which can be useful for this
- Klonoar 3y agopub(crate) in Rust somewhat does this.
- rakenodiax 3y agoNot to mention cfg(test)
- Supermancho 3y agoGo has this. Python has this (_ access). package-private allows you to write tests if the tests are in the same namespace (Java langs). Class Access Modifiers were for controlling property and method inheritance, which has been bastardized into "CAMs tell you the API", because it's convenient. An object's API can be defined by an interface (following traditional OOP conventions), allowing CAMs to be used for their original orthogonal purpose. In practice, developers don't want to make an interface when they can slap a CAM on it and say "good enough". Some language don't even support interfaces, pushing the practice. So here we are with the wrong abstraction.
- scruple 3y ago> Python has this (_ access). What exactly is being referenced here?
- Supermancho 3y ago> I wish that my programming languages had a "public for testing only" scope. > Python has this (_ access) Bypassing CAMs is useful for testing. Python has a mechanism, which is used for that^...regardless of the intent of the feature. ^Underscores are a partially enforced convention for private methods. If your import stripped your access to an attribute, you can still access via __getattribute__() which reaches into the hierarchy. There are other tricks as well. You might call this a special method lookup.
- BerislavLopac 3y agoAnd which mechanism is that exactly?
- edgyquant 3y agoThe one they clearly explained in the comment, using __get_attribute__
- deleted 3y ago
- Yodel0914 3y agoYou can do this in C# by labeling something as internal, but available to certain named assemblies, eg: [assembly: InternalsVisibleTo("UnitTests")]
- pkolaczk 3y agoRust has it. Just annotate your code with `#[cfg(test)]`.
- jiehong 3y agoI think Java gave 2 to ways to deal with this: There is “public” within a module, and “public” for other modules. This is not on a per method basis, though. And you can make a method “package-private”, and you can then test it right a way.
- magicalhippo 3y agoI put things like that in a separate namespace. If my namespace is Foobar I'll have a Foobar.Impl namespace. One of the lessons I've learned is that very little needs to be private, and there's a lot of advantage of not having things private. Putting that in a clearly defined namespace allows access when needed, for testing or workarounds, while conveying the needed "if you use this you're on your own".