proposal: functional assertions, a case for assert_equal, assert_match, and possibly more

153 views
Skip to first unread message

Jaap Frolich

unread,
Sep 29, 2016, 6:23:45 AM9/29/16
to elixir-lang-core
Probably you have run into this: if you have slightly more complex tests than testing the output of a single function, you need assignment and then assert that assignment with an operator. Consider this controller test in phoenix:

conn =
  build_conn
()
 
|> post("/upload_content_cover", params)


assert %{"success" => true} = json_response(conn, 200)


with an `assert_match` function this translates to the following:

build_conn()
|> post("/upload_content_cover", params)
|> json_response(conn, 200)
|> assert_match(%{"success" => true})


I prefer the latter, because it is more declarative. 

My issue with using operators in assertions, is that while improving readability in some cases, they are not very functional constructs, and thus do not compose well. Having a functional equivalent for the assertions, makes sense in a functional language in my opinion.

I can also see why this should be a library, keeping the assertion library less complex. Just would like to share my thinking. I'm also interested in feedback, and how I might be wrong :).

See the following pull request for an implementation: https://github.com/elixir-lang/elixir/pull/5259.

Eric Entin

unread,
Sep 29, 2016, 12:39:47 PM9/29/16
to elixir-lang-core
I disagree that the latter is more declarative than the former. They are just two different ways of writing the same thing. In fact, they're both fairly imperative. :)

Pipes are awesome, but IMO they are a tool for convenience, and not the only way that clean, idiomatic Elixir code can be structured. I think the number of asserts that you will eventually have to implement here is another good argument against this, as people reading your code will now have to know both the standard Elixir operators as well as the names of the special matchers you create.

I can definitely see your reasons for wanting this, so I think a library would be welcome, but I'm not in support of this being added to core at this time.

Ben Wilson

unread,
Sep 29, 2016, 1:51:14 PM9/29/16
to elixir-lang-core
I also disagree that it's more declarative.

In the standard ExUnit case, you have some setup code, and then the assertion is a clear and easily distinct line. It's clear what is the pattern, and what its being matched against.

both = and the existing match? function take the pattern on the LHS so assert_match in particular is a bit odd because it's now on the RHS.

Jaap Frolich

unread,
Sep 30, 2016, 1:01:30 AM9/30/16
to elixir-lang-core
Thanks,

It seems that opinions differ about the incremental improvement of putting this in. After thinking about it I also think it is probably better to keep it simple in the core language, and no reason for it not to be a library for functional programming aficionados, and syntax nitpicks :). If you do not worry how your code looks indeed the same can be accomplished using:

|> Kernel.==(expected_result)
|> assert


with match? we have to create a function to swap the arguments, and you can do the same.

I published it as assert_functional (https://hex.pm/packages/assert_functional), and I used it in the tests of another package (if you are interested how to apply it) if_ok (https://hex.pm/packages/if_ok).

Thanks for your feedback. Always interesting to build up a body of knowledge about how the community thinks about a particular subject.

@eric: Why do you think they are both imperative, and how would you make them more declarative? Very interested!

Cheers,

Jaap

Eric Entin

unread,
Sep 30, 2016, 10:21:01 AM9/30/16
to elixir-lang-core
I think that unit tests such as they exist in Elixir, which is an imperative functional language, IMO, are inherently imperative. Property tests would be a nice example of a more declarative testing style.

Ben Wilson

unread,
Sep 30, 2016, 5:35:16 PM9/30/16
to elixir-lang-core
When I think of imperative programming I think of programs with lots of statements that mutate state. When I think of functional programming I think of programs which model computation as inputs and outputs.

Elixir does have some impurity, but it has no statements, and pure functions constitute an enormous portion of what you write. I'm not sure "imperative functional language" is a thing.

This however is diverging heavily from the original topic.

Eric Entin

unread,
Sep 30, 2016, 5:43:43 PM9/30/16
to elixir-lang-core
That's definitely fair to say, Ben, though I will have to say that as far as other functional languages go, Elixir *looks* pretty imperative. :)

José Valim

unread,
Sep 30, 2016, 5:54:40 PM9/30/16
to elixir-l...@googlegroups.com
That's definitely fair to say, Ben, though I will have to say that as far as other functional languages go, Elixir *looks* pretty imperative. :)

You probably mean to say Elixir is *sequential*. Imperative programming definition focuses a lot on changing the program state, which is something we minimize in Elixir. For example, using for-loops for mutating an array is an imperative construct, in Elixir we would use Enum.map or recursion, which are on the functional/declarative side.

Eric Entin

unread,
Sep 30, 2016, 5:55:36 PM9/30/16
to elixir-lang-core, jose....@plataformatec.com.br
Yes, thanks José. :)

Jaap Frolich

unread,
Oct 6, 2016, 11:43:02 AM10/6/16
to elixir-lang-core, jose....@plataformatec.com.br
Thanks for all the wisdom in this thread! :)
Reply all
Reply to author
Forward
0 new messages