1
votes

I am trying to create a test case to reliably handle the case where there is a collision for a value in the database. When the user performs some action in my application a random 12 digit number is saved to the database attached to that action. The number is padded to 12 digits if it isn't the full length. If that number already exists in the database then the program picks another random number.

This probably sounds dumb but the expected user base is likely going to be less than 100-1000 users.

My code looks something like

def gen_random_unique() do
  unique = (:rand.uniform(1_000_000_000_000) - 1)
  |> Integer.to_string()
  |> String.pad_leading(12, ["0"])

  case get_from_database(unique) do
    nil ->
      unique
    _ ->
      gen_random_unique()
  end
end

Apart from testing the second condition millions of times until it passes, is there an easier way in Elixir to force that path? Since the function is recursive I'm not sure how I could mock it only on the first call (if that's the path I need to take.)

Thank you!

1
You could make the limit an argument to the function with a default value of 1_000_000_000_000 and in tests pass it a smaller value, e.g. 100.Dogbert
Why not just have a unique constraint on the database level and it will report an error if it already exists? You may also have the ability to write a function in your database that would completely avoid needing to generate and check the value in the application. Is there any reason you don't just use a UUID instead of a randomly generated number?Justin Wood
I would use a UUID but it's a string that a user can type to view the record. I was also thinking I could just make the generation process more deterministic but still 12 characters. Obviously a UUID would be quite the burden to make a user type. :PDylan Aspden

1 Answers

1
votes

Looks like you're doing unit test with coverage.

Why not have 2 separate tests with different mocking of get_from_database so that you can test both case branches.