Marcus

Marcus

Prove is a little and experimental lib that provides the macros prove and batch to use in ExUnit.Case.

A prove is just helpful for elementary tests. Prove generates one test with one assert for every prove.

Example:

defmodule NumTest do
  use ExUnit.Case

  import Prove

  defmodule Num do
    def check(0), do: :zero

    def check(x) when is_integer(x) do
      case rem(x, 2) do
        0 -> :even
        1 -> :odd
      end
    end

    def check(_), do: :error
  end

  describe "check/1" do
    prove Num.check(0) == :zero

    batch "returns :odd or :even" do
      prove Num.check(1) == :odd
      prove Num.check(2) == :even
      prove "for big num", Num.check(2_000) == :even
    end

    batch "returns :error" do
      prove Num.check("1") == :error
      prove Num.check(nil) == :error
    end
  end
end

The example above generates the following tests:

$> mix test test/num_test.exs --trace --seed 0

NumTest [test/num_test.exs]
  * prove check/1 (1) (0.00ms) [L#20]
  * prove check/1 returns :odd or :even (1) (0.00ms) [L#23]
  * prove check/1 returns :odd or :even (2) (0.00ms) [L#24]
  * prove check/1 returns :odd or :even for big num (1) (0.00ms) [L#25]
  * prove check/1 returns :error (1) (0.00ms) [L#29]
  * prove check/1 returns :error (2) (0.00ms) [L#30]


Finished in 0.08 seconds (0.00s async, 0.08s sync)
6 proves, 0 failures

Randomized with seed 0

The benefit of prove is that tests with multiple asserts can be avoided.
The example above with regular tests:

...
  describe "check/1" do
    test "returns :zero" do
      assert Num.check(0) == :zero
    end

    test "returns :odd or :even" do
      assert Num.check(1) == :odd
      assert Num.check(2) == :even
      assert Num.check(2_000) == :even
    end

    test "returns :error" do
      assert Num.check("1") == :error
      assert Num.check(nil) == :error
    end
  end
...
$> mix test test/num_test.exs --trace --seed 0

NumTest [test/num_test.exs]
  * test check/1 returns :zero (0.00ms) [L#36]
  * test check/1 returns :odd or :even (0.00ms) [L#40]
  * test check/1 returns :error (0.00ms) [L#46]


Finished in 0.03 seconds (0.00s async, 0.03s sync)
3 tests, 0 failures

Randomized with seed 0

You can find another example in datix.

The disadvantage of these macros is that the tests are containing fewer descriptions. For this reason and also if a prove looks too complicated, a regular test is to prefer.

Showing Posts 1 to 8

dimitarvp

dimitarvp

I wonder how will the feature of breaking apart multiple prove statements to multiple test + assert blocks work with stateful tests, e.g. Phoenix+Ecto app tests? Example:

describe "create and list users" do
  prove Repo.insert(...) == {:ok, %User{}}
  prove Repo.all(User) == [%User{}]
end

:point_up: will this break Ecto’s sandbox? If this actually gets broken down to 2x test + assert blocks then likely the second test/block will fail?

Marcus

Marcus OP

Yes this would break Ecto’s sandbox and even when not the proves/tests would be executed in random order. So, prove makes just sense for little and pure functions. If you have to think about how to write a test with prove then test is the better choice.

thojanssens1

thojanssens1

When using batch/prove there’s no more value using prove rather than test/assert?

    batch "returns :error" do
      prove Num.check("1") == :error
      prove Num.check(nil) == :error
    end
    test "returns :error" do
      assert Num.check("1") == :error
      assert Num.check(nil) == :error
    end

You don’t save any code here while saving code is the purpose of prove, if I understood correctly. It’s a little weird, at least to have introduced batch. Or maybe I missed something.

IloSophiep

IloSophiep

I think the advantage of prove in these situations is, that it converts each prove to its own test case.

In your example with test you end up with one test case and it has two asserts in it. You need to check on failure which assert failed and the ones after the failed one are not executed / evaluated while the first one fails.

The prove example though creates two test cases, each with one assert. Both test cases are independent and on failure you instantly know which assert / prove is the problem.

And then batch just allows one to group multiple proves so they all start with the same “prefix”, so you get a bit more context.

At least that’s how I understood everything.

thojanssens1

thojanssens1

That would make sense but that is not what @Marcus wrote above. He wrote the equivalent of batch with three proves as one test with three asserts.

thojanssens1

thojanssens1

But you’re right, I see that the resulting output for batch/prove is as you described. Thank you.

Marcus

Marcus OP

@thojanssens1 it works as @IloSophiep describes. But you’re right @thojanssens1, the documentation doesn’t explain it well and neither does my post. I will update the docs. @thojanssens1, @IloSophiep thanks for your posts.

strzibny

strzibny

Nice little idea!

— All posts loaded —

Where Next? Top

Trending in Announcing Top

restlessronin
The repo is at GitHub - cyberchitta/openai_ex: Community maintained Elixir library for OpenAI API · GitHub. Docs are at OpenaiEx User Gu...
152 12366 136
New
type1fool
WebAuthnLiveComponent WebAuthnComponents See this post about renaming the package. Passwordless authentication for Phoenix LiveView app...
New
mudasobwa
I fully migrated to my own harness from Anthropic/Gemini and I think it’s time to share it. Welcome DSH, the DeepSeek Harness, fully writ...
New
ausimian
Castle is a package I put together to assist with building Elixir releases capable of being live-upgraded via the ‘official’ release hand...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
ausimian
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New
kip
In 2021 I started a new library called Tempo with the objective of modelling time as a set of intervals - not as instants. In 2022 I gave...
New

Other Trending Topics Top

budgie
A little off-topic, but I feel like people here have a good head on their shoulders. I used to be quite good at making software. Was luc...
New
KristerV
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
juhalehtonen
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
New
budgie
I love Elixir. It’s one of 2 programming languages I’ve ever fallen in love with. But I don’t use it anymore. Serverless was the promis...
New
OndrejValenta
(I just needed to vent somewhere and LinkedIn is full of hope, or hype, I’m not sure which exactly) AI dream has many faces, but general...
New
Null-logic-0
What IDE or editor are you using for Elixir development? Personally, I use Zed, and I really like it, but sometimes I wish there were a ...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews