pierrelegall

pierrelegall

Explicit vs DRY tests

Hello alchemists! :woman_scientist: :man_scientist:

Tests are supposed to be readable/maintainable as every code should be in a perfect world. And explicitness is a good thing for readability.

Beginning my “one kata per day”, I wrote FizzBuzz tests in two ways. I don’t really know which style I prefer: one is very explicit and less concise. The other one is more in a DRY style.

What’s your opinion about this? :face_with_monocle:

Version 1:

defmodule Kata.FizzBuzz.Test do
  use ExUnit.Case

  import Kata.FizzBuzz

  test "1, 2, 4, 7, 8 returns number as a string" do
    assert fizz_buzz(1) == "1"
    assert fizz_buzz(2) == "2"
    assert fizz_buzz(4) == "4"
    assert fizz_buzz(7) == "7"
    assert fizz_buzz(8) == "8"
  end

  test "3, 6, 9, 12 returns Fizz" do
    assert fizz_buzz(3) == "Fizz"
    assert fizz_buzz(6) == "Fizz"
    assert fizz_buzz(9) == "Fizz"
    assert fizz_buzz(12) == "Fizz"
  end

  test "5, 10, 20, 25 returns Buzz" do
    assert fizz_buzz(5) == "Buzz"
    assert fizz_buzz(10) == "Buzz"
    assert fizz_buzz(20) == "Buzz"
    assert fizz_buzz(25) == "Buzz"
  end

  test "15, 30, 45, 60 returns FizzBuzz" do
    assert fizz_buzz(15) == "FizzBuzz"
    assert fizz_buzz(30) == "FizzBuzz"
    assert fizz_buzz(45) == "FizzBuzz"
    assert fizz_buzz(60) == "FizzBuzz"
  end
end

Version 2:

defmodule Kata.FizzBuzz.Test do
  use ExUnit.Case

  import Kata.FizzBuzz

  test "1, 2, 4, 7, 8 returns number as a string" do
    [1, 2, 4, 7, 8]
    |> Enum.each(fn n -> assert fizz_buzz(n) == "#{n}" end)
  end

  test "3, 6, 9, 12 returns Fizz" do
    [3, 6, 9, 12]
    |> Enum.each(fn n -> assert fizz_buzz(n) == "Fizz" end)
  end

  test "5, 10, 20, 25 returns Buzz" do
    [5, 10, 20, 25]
    |> Enum.each(fn n -> assert fizz_buzz(n) == "Buzz" end)
  end

  test "15, 30, 45, 60 returns FizzBuzz" do
    [15, 30, 45, 60]
    |> Enum.each(fn n -> assert fizz_buzz(n) == "FizzBuzz" end)
  end
end

Most Liked

hauleth

hauleth

My approach, as your is IMHO too repeating the implementation:

defmodule Kata.FizzBuzzTest do
  use ExUnit.Case
  use ExUnitProperties

  property "multiples of 3 contains `Fizz`" do
    check all n <- integer() do
      result = fizz_buzz(n * 3)
      assert String.contains?(result, "Fizz")
    end
  end

  property "multiples of 5 contains `Buzz`" do
    check all n <- integer() do
      result = fizz_buzz(n * 5)
      assert String.contains?(result, "Buzz")
    end
  end

  property "returned value is a binary" do
    check all n <- integer() do
      assert is_binary(fizz_buzz(n))
    end
  end

  property "result for 'plain' values is stringified integer" do
    check all n <- integer(), rem(n, 3) * rem(n, 5) != 0 do
      assert fizz_buzz(n) == Integer.to_string(n)
    end
  end
end

There probably could be some additional properties like the above

tfwright

tfwright

I think I am an outlier when it comes to tests, but I would not include any logic to generate assertions in unit tests. I would just choose one type of input for each type of output, with a test for each. If this logic was extra critical or issues keep popping up with unexpected inputs, I guess I would consider adding some sort of property based test to supplement the unit tests, but I would consider carefully before doing it.

LostKobrakai

LostKobrakai

To me the test labels also stand out the most. They should at best specify what needs to happen and not just repeat the examples.

At that point property testing (e.g. using stream_data) might become the more appropriate tool to use.

Last Post!

jarmo

jarmo

I always prefer explicit tests. Yes, they are more tedious to write, but much easier to understand when they start to fail.

Also, if trying to keep tests as DRY as production code then at one point they might get so complex that they need their own tests.

Where Next?

Popular in Discussions Top

scouten
I’m looking for a host for the server part of a small (personal) side project that I’m working on. It’s currently written in Node.js and ...
New
und0ck3d
Hello everyone! A few days ago I’ve created a topic here about how people were creating CMSs with Elixir and Phoenix. I’ve been studying...
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
tmbb
This is a post to discuss the new Phoenix LiveView functionality. From Chris’s talk, it appears that they generate all HTML on the serve...
342 18584 126
New
mikl
I wanted to capitalize a string, and tried using String.capitalize(). That generally works well, until you try to capitalize a word like...
New
cvkmohan
The upcoming Phoenix 1.6 release looks very interesting. Became a habit to watch the commits - and - what they are bringing in. phx.gen...
New
arcanemachine
https://nitter.net/josevalim/status/1744395345872683471 https://twitter.com/josevalim/status/1744395345872683471
New

Other popular topics Top

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
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New

We're in Beta

About us Mission Statement