This, 100%. Unfortunately, private functions aren’t testable without jumping through some hoops. I found a macro on SO somewhere for defining functions that expands to
def if the environment is
defp otherwise. It’s a hack and I only use it in my own code, but I wish it were built in.
(And inb4 “private functions should be so simple they don’t require testing”. IMO it’s reasonable to have complex functions which nonetheless should not be part of the public interface.)
There are few solutions for that problem and there is still no consensus how to deal with testing private functions in Elixir, there are few possibilities though:
Do not test them at all
And when you need testing, then export them to separate, internal and undocumented, module.
Expose all functions as public in testing:
defmodule Foo do
if Mix.env == :test do
defp foo, do: 10
And then all functions are exported by default.
Define tests in line within module
This technique is sometimes used in Erlang with EUnit, but I have written simple macros that allows you to achieve similar solution in Elixir with ExUnit. Not perfect (again), but it is some kind of solution.
However in general I agree to the fact that in most cases you should not test private functions, and if you need to do so, then in most cases you probably need to extract that functionality to separate module anyway.
Consider a 1-liner that wraps up a non-trivial regex match & replace–you’d better the hell test that
Typespec syntax would be unified with, or auto-generated from, guards.
This would only work if every type has a unique runtime representation, which is quite limiting.
For example modules and atoms are the same according to guards, as are
Elixir with Type Inference, Algebraic Data Types
If I might self publicise for a moment, I’m working on a Erlang/Elixir like language with full type inference and ADTs, perhaps you might find it interesting.
Here’s a thread with more detail: Gleam, a statically typed language for the Erlang VM
Sorry, suppose we will not use it in production