I started writing some functions to help test assertions on maps.
Let's say I have the following map:
#{a => 0, b => 2}
And after calling a function in my business logic I expect the map to look like this:
#{a => 1, b => 2}
In other words, I expect
- the map to have the same number of keys after the update
- the value of
a
to change from 0 to 1 - the value of
b
unchanged
I could just leave this test to pattern matching, however, if I have a large map with a lot of keys (and perhaps even a lot of submaps) it is not obvious where the problem might be - at least it takes some time to find the problem (maybe some values which I expected to be updated were not - or maybe there are some extra keys, etc, etc - I hope you get the point).
So as a start, I came up with the following helper function in my module:
-module(asserts).
-include_lib("eunit/include/eunit.hrl").
maps_assert_map_has_updated_values(BaseMap, Updates, ResultingMap) ->
BaseMapKeys = lists:sort(maps:keys(BaseMap)),
ResultingMapKeys = lists:sort(maps:keys(ResultingMap)),
UpdatesKeys = lists:sort(maps:keys(Updates)),
BaseMapWithoutUpdates = maps:without(UpdatesKeys, BaseMap),
BaseMapKeysWithoutUpdates = lists:sort(maps:keys(BaseMapWithoutUpdates)),
ResultingMapWithoutUpdates = maps:without(UpdatesKeys, ResultingMap),
[
?_assertEqual(BaseMapKeys, ResultingMapKeys),
lists:foldl(
fun(Key, Acc) -> [?_assertEqual({Key, maps:get(Key, Updates)},
{Key, maps:get(Key, ResultingMap)}) | Acc] end,
[],
UpdatesKeys
),
lists:foldl(
fun(Key, Acc) -> [?_assertEqual({Key, true},
{Key, maps:is_key(Key, ResultingMap)}) | Acc] end,
[],
UpdatesKeys
),
lists:foldl(
fun(Key, Acc) -> [?_assertEqual({Key, maps:get(Key, BaseMapWithoutUpdates)},
{Key, maps:get(Key, ResultingMapWithoutUpdates)}) | Acc] end,
[],
BaseMapKeysWithoutUpdates
)
].
I call this from another module, which is executed by eunit:
-module(map_tests).
-include_lib("eunit/include/eunit.hrl").
simple_map_test_() ->
asserts:maps_assert_map_has_updated_values(
#{a => 0, b => 2},
#{a => 1},
#{a => 1, b => 3}).
And I get the following error message:
asserts:30: maps_assert_map_has_updated_values...*failed* in function asserts:'-maps_assert_map_has_updated_values/3-fun-8-'/3 (test/asserts.erl, line 31)
**error:{assertEqual_failed,[{module,asserts},
{line,31},
{expression,"{ Key , maps : get ( Key , ResultingMapWithoutUpdates ) }"},
{expected,{b,2}},
{value,{b,3}}]}
Which is almost what I want in that it reports the problematic key and the problematic values in the map, however it reports the error being in the asserts
module, even though I am interested in seeing the actual test that failed, not the reference to the assertions module. I thought test generators were good for exactly that, but I wasn't able to get this working in that way.
Is there any way in which I can make eunit
report the actual test module (map_tests
, function/test simple_map_test
line X) instead of my asserts
module?