{"id":17968543,"url":"https://github.com/devonestes/assertions","last_synced_at":"2025-05-15T06:07:02.512Z","repository":{"id":45479083,"uuid":"159792869","full_name":"devonestes/assertions","owner":"devonestes","description":"Helpful assertions for ExUnit","archived":false,"fork":false,"pushed_at":"2025-04-22T06:58:59.000Z","size":110,"stargazers_count":146,"open_issues_count":8,"forks_count":33,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-04-22T07:44:16.697Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/devonestes.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-11-30T08:32:55.000Z","updated_at":"2025-04-22T06:59:03.000Z","dependencies_parsed_at":"2024-12-06T14:03:19.472Z","dependency_job_id":null,"html_url":"https://github.com/devonestes/assertions","commit_stats":{"total_commits":46,"total_committers":6,"mean_commits":7.666666666666667,"dds":"0.15217391304347827","last_synced_commit":"8b353fd941baee8b71181d4e8722c587a5aede87"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devonestes%2Fassertions","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devonestes%2Fassertions/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devonestes%2Fassertions/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devonestes%2Fassertions/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/devonestes","download_url":"https://codeload.github.com/devonestes/assertions/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254283339,"owners_count":22045140,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-29T14:40:40.591Z","updated_at":"2025-05-15T06:07:02.429Z","avatar_url":"https://github.com/devonestes.png","language":"Elixir","readme":"# Assertions [![Hex Version](https://img.shields.io/hexpm/v/assertions.svg)](https://hex.pm/packages/assertions) [![Build Status](https://travis-ci.org/devonestes/assertions.svg?branch=master)](https://travis-ci.org/devonestes/assertions)\n\n## Installation\n\nAdd `assertions` to your list of dependencies in `mix.exs`:\n\n```elixir\ndef deps do\n  [{:assertions, \"~\u003e 0.20\", only: :test}]\nend\n```\n\n## Usage\n\n### Importing\n\nIf you only want some assertions in a given module, then import just the\nfunctions that you want to use. Otherwise you can simply call `import\nAssertions` and all assertions will be directly available to your test code.\n\n```elixir\ndef UsersTest do\n  use ExUnit.Case, async: true\n\n  require Assertions\n  import Assertions, only: [assert_lists_equal: 2]\n\n  # ...\nend\n```\n\nBecause these assertions are all macros, `Assertions` must be `require`d first\nif you want to call a function like `Assertions.assert_map_in_list/3`.\n\nImporting assertions in an existing test case (like `MyApp.DataCase` in a\nPhoenix application) is typically recommended.\n\nHere is an example of how you'd add assertions to your `MyApp.DataCase`:\n```elixir\ndefmodule MayApp.DataCase do\n  use ExUnit.CaseTemplate\n\n  using do\n    quote do\n      import Ecto\n      import Ecto.Changeset\n      import Ecto.Query\n\n      import MyApp.DataCase\n\n      # Add the following line\n      import Assertions\n    end\n  end\nend\n```\n\n### Assertions.Case\n\nIf you want to have all assertions available to you by default, you can use the\nprovided `Assertions.Case` macro. This is a very small wrapper around\n`ExUnit.Case`, and imports all assertions for your use.\n\n```elixir\ndef MyApp.UserTest do\n  use Assertions.Case, async: true\n\n  # ...\nend\n```\n\nBut importing assertions in an existing test case (like `MyApp.DataCase` in a\nPhoenix application) is typically recommended.\n\n## Why use `assertions`?\n\nThere are three things this library offers:\n\n1) Concise, expressive assertions for common types of tests\n2) Flexibility through composition\n3) Exceptional error messages\n\nLet's look at examples of all of these points. Let's say you have the following\ntest:\n\n```elixir\ndefmodule UsersTest do\n  use ExUnit.Case, async: true\n\n  describe \"update_all/2\" do\n    test \"updates the given users in the database and returns those updated users\" do\n      alice = Factory.insert(:user, name: \"Alice\")\n      bob = Factory.insert(:user, name: \"Bob\")\n\n      updated_names = \n        [{alice, %{name: \"Alice A.\"}, {bob, %{name: \"Bob B.\"}}}]\n        |\u003e Users.update_all()\n        |\u003e Enum.map(\u0026 \u00261.name)\n\n      all_user_names =\n        User\n        |\u003e Repo.all()\n        |\u003e Enum.map(\u0026 \u00261.name)\n\n      Enum.each([\"Alice A.\", \"Bob B.\"], fn name -\u003e\n        assert name in updated_names\n        assert name in all_user_names\n      end\n    end\n  end\nend\n```\n\nTesting elements in lists is a very common thing to do, but it's also very\ntricky! If you want to test those lists, you can't assert that they're equal\nbecause order matters with lists. Also, with those structs, you can't compare\nthem directly because maybe there are associations that might be loaded in one\nstruct but not loaded in the other. The above test is the best you can do to\naccurately test those changes with the standard testing tools.\n\n### Expressive assertions\n\nBut, with `assertions`, you can write that test like this:\n\n```elixir\ndefmodule UsersTest do\n  use ExUnit.Case, async: true\n  import Assertions, only: [assert_lists_equal: 2]\n\n  describe \"update_all/2\" do\n    test \"updates the given users in the database and returns those updated users\" do\n      alice = Factory.insert(:user, name: \"Alice\")\n      bob = Factory.insert(:user, name: \"Bob\")\n\n      result = Users.update_all([{alice, %{name: \"Alice A.\"}, {bob, %{name: \"Bob B.\"}}}\n\n      result\n        |\u003e Enum.map(\u0026 \u00261.name)\n        |\u003e assert_lists_equal([\"Alice A.\", \"Bob B.\"])\n\n      assert_lists_equal(result, Users.list_all(), \u0026assert_structs_equal(\u00261, \u00262, [:name]))\n    end\n  end\nend\n```\n\n`assert_lists_equal` asserts that the two lists are equal without taking order\ninto account, which is most often the assertion that we want to make when\ncomparing lists.\n\n### Flexibility through composition\n\nBut `assert_lists_equal` also solves the other problem we had when we wanted to\ncompare lists of structs. That second assertion:\n\n```elixir\nassert_lists_equal(result, Users.list_all(), \u0026assert_structs_equal(\u00261, \u00262, [:name]))\n```\n\nis comparing that the two lists are equal, but we give it a custom comparison\nfunction. If we were to just use `assert_lists_equal(results, Users.list_all())`,\nthen all values for all keys in those structs must be equal for them to be\nconsidered equal, and this can be very error prone, especially when dealing with\nstructs used as Ecto resources that can have associations that are either loaded\nor not loaded.\n\nThis ability to compose behavior of assertions lets you easily customize your\nassertions for each of your tests.\n\n### Exceptional error messages\n\n`assertions` always tries to give you the most helpful error messages possible\nfor any test failures to make it easy to see what went wrong and how to fix it.\nLets look at a different test:\n\n```elixir\ntest \"a map in a list matches the value of this other map\" do\n  map = %{key: :value, stores: :are, really: :helpful}\n\n  list = [\n    %{big: :map, with: :lots, of: :keys},\n    %{another: :big, store: :with, key: :values}\n  ]\n\n  assert Enum.any?(list, fn map_in_list -\u003e\n            Map.get(map_in_list, :key) == map.key\n          end)\nend\n```\n\nThe output you get from that failure looks like this:\n\n```\n     Expected truthy, got false\n     code: assert Enum.any?(list, fn map_in_list -\u003e Map.get(map_in_list, :key) == map.key() end)\n     arguments:\n\n         # 1\n         [\n           %{big: :map, of: :keys, with: :lots},\n           %{another: :big, key: :values, store: :with}\n         ]\n\n         # 2\n         #Function\u003c21.25555998/1 in Assertions.FailureExamples.\"test example\"/1\u003e\n\n     stacktrace:\n       test/failure_examples.exs:207: (test)\n```\n\nThat's not really helpful. What we wanted to know was essentially \"is a map with\nthe same values for a certain key in this list?\", and we got no help in finding\nwhat went wrong. With `assertions` we can write that same assertion like this:\n\n```elixir\ntest \"a map in a list matches the value of this other map\" do\n  map = %{key: :value, stores: :are, really: :helpful}\n\n  list = [\n    %{big: :map, with: :lots, of: :keys},\n    %{another: :big, store: :with, key: :values}\n  ]\n\n  assert_map_in_list(map, list, [:key])\nend\n```\n\nAnd then the output looks like this:\n\n```\n     Map matching the values for keys `:key` not found\n     code:  assert_map_in_list(map, list, [:key])\n     arguments:\n\n         # 1\n         %{key: :value, really: :helpful, stores: :are}\n\n         # 2\n         [\n           %{big: :map, of: :keys, with: :lots},\n           %{another: :big, key: :values, store: :with}\n         ]\n\n     left:  %{key: :value}\n     right: [%{}, %{key: :values}]\n     stacktrace:\n       test/failure_examples.exs:206: (test)\n```\n\nThe error message there in the `left` and `right` keys shrinks down the output\nto only show us the relevant information. I can see here that one map didn't\ncontain the key we wanted, and the value was different in the other.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevonestes%2Fassertions","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdevonestes%2Fassertions","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevonestes%2Fassertions/lists"}