spinlock99

spinlock99

Testing Private Functions

I always wind up not having private functions in my modules because you can’t test them. I really have a strong preference for TDD and - at this point - I can barely write a function without having a test first. I recently had a function that is stupid simple:

def char_value(char), do: char - ?@

The point is to convert an uppercase letter to a numerical value (i.e. A == 1, B == 2, etc…). This is just a helper function that I’d never want to expose outside of the module, it’s logic is very simple, but It was tricky (for me) to figure out that ?@ == 64 and gave me the value I want. I suppose I could have just made the function char - ?A + 1 but this is just an example of when a function (which should be private IMO) benefits from being tested.

Am I just thinking about private functions wrong? To me, a private function is a helper for simplifying the complexity of public functions in the module. Should I just think of private functions as functions that are themselves simple enough to not need a test?

Most Liked

sodapopcan

sodapopcan

You could start a holy war with questions like this! :upside_down_face:

I’m a TDDer myself and I do not see value in testing private functions in that they mostly appear later as I’m refactoring. However, sometimes you can find yourself with a single function that does a lot of stuff. In those cases, you can always move these function to a sub “private” module (@moduledoc false) and write tests for them there (though personally when I do this I just end up deleting the tests when I’m done as I just want tests for my public interface).

In the case of your example, that is a candidate to just be moved to an external helper module. It’s one of those functions that does one small thing very well, so there’s no harm in other people using it, especially since it has tests! However, if you really want to keep it private in your current module, then the tests for whatever public function you are using this for will certainly cover it. If you really want to start with just a test for that one line, then I’d do what I suggested above (and sanctioned by Sandi Metz herself ;)), make it public, write a test for it and when you’re done, or at least when you have public functions that consume it, delete the test and make it private.

Otherwise, keeping tests for things at this level of granularity makes reafactorting a massive pain. It’s also exhausting for readers (although I guess no one reads code anymore and LLMs don’t get exhausted /s)

tfwright

tfwright

I don’t think this is unquestionably true. Maybe debatable, but I’d strongly argue that one of the underrated benefits of unit tests is that they document what a module does. If you maintain tests for private functions you are now also documenting how it does it. Not terrible, but why do that when you can write a test for the caller than exercises the private function?

dimitarvp

dimitarvp

Private functions to me should be:

  • An implementation detail;
  • A way to enforce boundaries.

If you find yourself needing to test private functions then it’s time to ask yourself or the team these questions:

  • Is it time to promote these functions into a public API and accept that any other module in the app can call them now?
  • Are you getting obsessive about testing every single thing? Indeed testing the public API and letting a private function fail an assertion as a part of that test is quite fine and not a reason to make private functions public.

I don’t agree with the argument that only libraries should carefully control what’s public. I’m currently working hard, together with Claude, to untangle quite the spaghetti code. It’s painful and it really drives home the point that scope and access creep are real problems.

Last Post!

Asd

Asd

Unused private functions are not compiled in the module, therefore Repatch cant access their code to make them public in tests. Try using this private function in a public one

Where Next?

Popular in Discussions Top

AstonJ
Please see the new poll here: Which code editor or IDE do you use? (Poll) (2022 Edition) It’s been a while since we first asked this, I...
208 31771 143
New
sergio
There’s a new TIOBE index report that came out that shows Elixir is still not in the top 50 used languages. It also goes on to call Elix...
New
rms.mrcs
A couple of days ago I was discussing with a friend about different approaches to write microservices. He said that if he was going to w...
New
Fl4m3Ph03n1x
Background This question comes mainly from my ignorance. Today is Black Friday, one of my favorite days of the year to buy books. One boo...
New
owaisqayum
I have a sample string sentence = "Hello, world ... 123 *** ^%&*())^% %%:>" From this string, I want to only keep the integers, ...
New
marciol
Please, let me know if this kind of discussion already took place in another topic . Hi all, how do you consider if is better to build ...
New
RudManusachi
What configs will make sense to put to runtime.exs? – A bit of how I configure apps: I have generic configs in config/config.exs, dev...
New

Other popular topics Top

JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New

We're in Beta

About us Mission Statement