{"id":30617455,"url":"https://github.com/curtd/testingutilities.jl","last_synced_at":"2025-08-30T10:10:38.656Z","repository":{"id":162072232,"uuid":"632619660","full_name":"curtd/TestingUtilities.jl","owner":"curtd","description":"Making testing your code slightly less painful, hopefully.","archived":false,"fork":false,"pushed_at":"2024-10-31T16:43:59.000Z","size":1074,"stargazers_count":10,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-22T20:34:57.304Z","etag":null,"topics":["julia","metaprogramming","testing"],"latest_commit_sha":null,"homepage":"","language":"Julia","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/curtd.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":"2023-04-25T19:35:26.000Z","updated_at":"2024-10-31T16:23:40.000Z","dependencies_parsed_at":"2024-04-23T19:42:08.882Z","dependency_job_id":"71478943-0a8a-4d02-bdf1-841159ec7ed2","html_url":"https://github.com/curtd/TestingUtilities.jl","commit_stats":null,"previous_names":["curtd/testingutilities.jl"],"tags_count":31,"template":false,"template_full_name":null,"purl":"pkg:github/curtd/TestingUtilities.jl","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/curtd%2FTestingUtilities.jl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/curtd%2FTestingUtilities.jl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/curtd%2FTestingUtilities.jl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/curtd%2FTestingUtilities.jl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/curtd","download_url":"https://codeload.github.com/curtd/TestingUtilities.jl/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/curtd%2FTestingUtilities.jl/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272834409,"owners_count":25001089,"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","status":"online","status_checked_at":"2025-08-30T02:00:09.474Z","response_time":77,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["julia","metaprogramming","testing"],"created_at":"2025-08-30T10:10:37.139Z","updated_at":"2025-08-30T10:10:38.643Z","avatar_url":"https://github.com/curtd.png","language":"Julia","funding_links":[],"categories":[],"sub_categories":[],"readme":"# TestingUtilities\n\n[![Stable](https://img.shields.io/badge/docs-stable-blue.svg)](https://curtd.github.io/TestingUtilities.jl/stable/)\n[![Dev](https://img.shields.io/badge/docs-dev-blue.svg)](https://curtd.github.io/TestingUtilities.jl/dev/)\n[![Build Status](https://github.com/curtd/TestingUtilities.jl/actions/workflows/CI.yml/badge.svg?branch=main)](https://github.com/curtd/TestingUtilities.jl/actions/workflows/CI.yml?query=branch%3Amain)\n[![Coverage Status](https://coveralls.io/repos/github/curtd/TestingUtilities.jl/badge.svg)](https://coveralls.io/github/curtd/TestingUtilities.jl)\n\n`TestingUtilities` provides macros for improving the visibility into your failing tests.\n\n# Macros\n## `@Test` \nAn expression invoking `@Test` outputs the value of (automatically-determined) variables of interest when the underlying test errors or fails. E.g., \n```julia\n    x = 1\n    @Test x^2 == 2\n```\n\nSample output:\n```\n    Test `x ^ 2 == 2` failed with values:\n    `x ^ 2` = 1\n    x = 1\n    Test Failed at REPL[278]:1\n     Expression: x ^ 2 == 2\n      Evaluated: false\n```\n\nThis macro can handle a number of more complicated combinations of Julia expressions, e.g., \n```julia\n    test_parity(a; is_odd::Bool) = mod(a,2) == (is_odd ? 1 : 0)\n    A = collect(1:10)\n    all_is_odd = (false, true)\n    @Test all([test_parity(a; is_odd) for a in A for is_odd in all_is_odd])\n```\n\nSample output:\n```\n    Test `all([test_parity(a; is_odd) for a = A for is_odd = all_is_odd])` failed with values:\n    `[test_parity(a; is_odd) for a = A for is_odd = all_is_odd]` = Bool[0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0]\n    A = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n```\n\nNo values are printed when the test passes. \n\n## `@test_cases` \nThe `@test_cases` macro allows you to compactly evaluate test expressions on test cases with the same underlying data fields, but differing values. The values of the specific test cases that cause each test expression to fail will be printed, similar to `@Test`. \n\nIf run as a standalone macro invocation, the tests will terminate at the first instance of failure, e.g., \n```julia\n    @test_cases begin \n        a | b | output \n        1 | 2 | 3\n        1 | 2 | 4\n        0 | 0 | 1\n        0 | 0 | -1\n        @test a + b == output\n    end\n```\n\nSample output:\n```\n    Test `a + b == output` failed with values:\n    ------\n    `a + b` = 3\n    output = 4\n    a = 1\n    b = 2\n```\n\nWhen run inside a `@testset`, all of the failing test values will be printed \n\n```julia\n    @testset \"Failing Test\" begin\n       @test_cases begin \n            a | b | output \n            1 | 2 | 3\n            1 | 2 | 4\n            0 | 0 | 1\n            0 | 0 | -1\n            @test a + b == output\n        end\n    end\n```\n\nSample output:\n```\n    Test `a + b == output` failed with values:\n    ------\n    `a + b` = 3\n    output = 4\n    a = 1\n    b = 2\n    ------\n    `a + b` = 0\n    output = 1\n    a = 0\n    b = 0\n    ------\n    `a + b` = 0\n    output = -1\n    a = 0\n    b = 0\n```\n\n## `@test_eventually`\nThe `@test_eventually` is used to test that a given test expression eventually returns true (i.e., passes within a prescribed timeout). You can use it to test, for instance, that blocking expressions eventually return within a given time limit or will throw a `TestTimedOutException` in your test set instead.\n\n```julia \n    @testset \"Timing Out Test\" begin\n        done = Ref(false)\n        f = (done)-\u003e(while !done[]; sleep(0.1) end; true)\n        \n        # Times out after 1s, checking every 10ms that a value has not returned\n        @test_eventually timeout=1s sleep=10ms f(done)\n        \n        # Test passes within the allotted timeout\n        g = @async (sleep(0.3); done[] = true)\n        @test_eventually timeout=1s sleep=10ms f(done)\n    end\n```\n\nSample output:\n```\n    Test `f(done)` failed:\n    Reason: Test took longer than 1000 milliseconds to pass\n    Values:\n    done = Base.RefValue{Bool}(false)\n    Timing Out Test: Error During Test at REPL[133]:6\n    Test threw exception\n    Expression: f(done)\n    \n    Test Summary:   | Pass  Error  Total  Time\n    Timing Out Test |    1      1      2  1.5s\n    ERROR: Some tests did not pass: 1 passed, 0 failed, 1 errored, 0 broken.\n```\n\n# Equality-Comparison Tests \nIf your test (using either of the above two macros) involves comparing the equality of two values `x::T` and `y::T`, if `T` is one of the types specified below, a failing test will show a nicely formatted message outlining the specific differences between them. \n\n## String \nIf `x` and `y` are of type `AbstractString`, a failing test will show the common prefix of these strings (if present) printed in green, followed by the differing components of each string in red. E.g., \n\n![Two strings whose common prefix is shown in green and whose differing suffixes are shown in red](docs/assets/string_diff1.png)\n\nIf you're unable to discern colour differences between green + red, you can set the styles of the displayed differences using the `TestingUtilities.set_show_diff_styles(; matching, differing)` method. The keyword arguments can be set to any `key =\u003e value` pair accepted by `Base.printstyled`, e.g.,\n\n![Two strings whose common prefix is shown in boldface and whose differing suffixes are shown as underlined](docs/assets/string_diff2.png)\n\n## DataFrames \nIf `x` and `y` are of type `AbstractDataFrame`, a failing test will show the reason that the two dataframes are not equal. E.g., \n\n- `x` and `y` do not have the same columns\n![Two dataframes with differing columns](docs/assets/df_diff1.png)\n\n- `x` and `y` have differing number of rows\n![Two dataframes with differing number of rows](docs/assets/df_diff2.png)\n\n- `x` and `y` have the same number of rows and the same columns, but differing values\n![Two dataframes with differing values](docs/assets/df_diff3.png)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcurtd%2Ftestingutilities.jl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcurtd%2Ftestingutilities.jl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcurtd%2Ftestingutilities.jl/lists"}