lamtrhieu

lamtrhieu

How to write tests for public functions with many complex private functions

Hi everyone,
I have a module with several public api and the implementation for these public require call to several private functions. Something like this

def foo do
  bar 
  baa 
  baz
end

defp baa do
...
end
defp baz do 
...
end
defp bar do
.....
end

And baa have 2 cases to test, baz have 3 cases, and bar have 5 cases. So if I just keep them as private functions inside 1 module, I need to write 2x3x5=30 unit tests.
So I refactor them to separate module and make them public so I just need to write 2+3+5=10 unit tests and some smoke tests for foo which don’t cover all the scenarios.

Is that approach ok and how I prevent users from misused my private module ? I just want the user to use my public module only.

Hope to hear your thoughts on this matter. Thanks

Most Liked

sasajuric

sasajuric

Author of Elixir In Action

It can already solve it today :slight_smile: Add use Boundary to the top-level module (e.g. context), and the cross-boundary calls to the internal ones will be reported. It’s still not fully usable, b/c the support for nested boundaries is lacking, but that’s definitely on the roadmap.

Boundary doesn’t do any mangling. It uses compilation tracer to collect all function/macro invocations, and then reports non-permitted cross-boundary calls.

It’s definitely not bulletproof. Breaking it is currently as easy as using apply to dynamically invoke the function. This can be detected though, and I plan to address it, but even then you can work around by constructing the module name dynamically.

All that said, boundary will make you work harder to introduce unwanted dependencies into your codebase.

chrismcg

chrismcg

It would certainly help stop “accidental” usage where someone who doesn’t understand the @moduledoc false idiom calls a function directly instead of through private api.

NobbZ

NobbZ

The convention is that internal modules are @moduledoc false, similar how internal functions are @doc false, though you have no way to enforce that no one will use them.

There is some prototype library defmodulep which hides modules by name doing some name mangling, but still, once someone figured out the mangled name, they can use the module anyway.

chrismcg

chrismcg

I wonder if boundaries will end up being the way to solve this in future. Make the functions public but enforce that only the parent module can call them outside of tests.

Where Next?

Popular in Questions Top

sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
Werner
Hi, I’m using Ubuntu 18.04 and after updating to OTP-24.0 yesterday i have this warning when I run “mix local.hex”: 14:57:30.512 [warn] ...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
vac
Hi, I'm quite new in Elixir and I'm trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and ...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lis...
New
LegitStack
I’m trying to make a websocket server in Phoenix or raw Elixir. I heard about gun, I think I could use cowboy, but since I’m not that sma...
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
hpopp
To simplify some tasks at work, I wrote and published this package yesterday. It’s a simple macro that enables Access behaviour on struct...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New

Other popular topics Top

jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod -- where is this set? Thanks.
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
polypush135
As many of you may have realized by now (sorry for all the posts here) I’ve been working on a db problem where I’m trying to aggregate a ...
New
chrismccord
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
chensan
I have a User schema with a :from_id field set to type :string: defmodule TweetBot.Repo.Migrations.CreateUsers do use Ecto.Migration ...
New
qwerescape
Is there a way to get the call stack or stack trace at any point in the code? Not from exceptions, but an expression that returns how the...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
Fl4m3Ph03n1x
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: ) Hello all, this is ...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New

We're in Beta

About us Mission Statement