{"id":18753025,"url":"https://github.com/spotify/java-hamcrest","last_synced_at":"2025-04-09T15:09:33.149Z","repository":{"id":15360681,"uuid":"77405221","full_name":"spotify/java-hamcrest","owner":"spotify","description":"Libraries that extend the Hamcrest matching library with useful matchers","archived":false,"fork":false,"pushed_at":"2024-02-07T12:50:32.000Z","size":222,"stargazers_count":86,"open_issues_count":5,"forks_count":16,"subscribers_count":18,"default_branch":"master","last_synced_at":"2025-04-09T15:09:28.018Z","etag":null,"topics":["hamcrest","java"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/spotify.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":"2016-12-26T20:23:31.000Z","updated_at":"2025-02-05T09:39:29.000Z","dependencies_parsed_at":"2023-01-13T18:23:19.004Z","dependency_job_id":"99735e0d-1322-4026-a76c-8d9d0a1c314f","html_url":"https://github.com/spotify/java-hamcrest","commit_stats":null,"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spotify%2Fjava-hamcrest","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spotify%2Fjava-hamcrest/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spotify%2Fjava-hamcrest/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spotify%2Fjava-hamcrest/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/spotify","download_url":"https://codeload.github.com/spotify/java-hamcrest/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248055282,"owners_count":21040157,"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":["hamcrest","java"],"created_at":"2024-11-07T17:23:52.675Z","updated_at":"2025-04-09T15:09:33.127Z","avatar_url":"https://github.com/spotify.png","language":"Java","readme":"# Spotify Hamcrest\n\n[![Build Status](https://github.com/spotify/java-hamcrest/actions/workflows/ci.yaml/badge.svg?branch=master)](https://github.com/spotify/java-hamcrest/actions/workflows/ci.yaml)\n[![codecov](https://codecov.io/gh/spotify/java-hamcrest/branch/master/graph/badge.svg)](https://codecov.io/gh/spotify/java-hamcrest)\n[![Maven Central](https://img.shields.io/maven-central/v/com.spotify/hamcrest.svg)](https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.spotify%22%20hamcrest*)\n[![License](https://img.shields.io/github/license/spotify/java-hamcrest.svg)](LICENSE)\n\nThis is a collection of libraries extending the Hamcrest matching\nlibrary with useful matchers. We consider this library in beta but use it\nin many of our internal projects.\n\n- [Spotify Hamcrest](#spotify-hamcrest)\n  - [Download](#download)\n  - [Getting Started](#getting-started)\n    - [POJO matchers](#pojo-matchers)\n    - [JSON matchers](#json-matchers)\n    - [java.util.Optional matchers](#javautiloptional-matchers)\n    - [Future matchers](#future-matchers)\n      - [raw `Future` matchers](#raw-future-matchers)\n      - [Java 8's `CompletableFuture` matchers](#java-8s-completablefuture-matchers)\n  - [Prerequisities](#prerequisities)\n  - [Releasing](#releasing)\n  - [Code of conduct](#code-of-conduct)\n  - [Ownership](#ownership)\n\n\n## Download\n\nEach of these modules is published to [Maven Central][maven-search] with the groupId of `com.spotify`.\nThe list of modules available is:\n\n* hamcrest-pojo\n* hamcrest-jackson\n* hamcrest-optional\n* hamcrest-future\n\n\n## Getting Started\n\n### POJO matchers\n[![Javadocs](http://www.javadoc.io/badge/com.spotify/hamcrest-pojo.svg?color=blue)](http://www.javadoc.io/doc/com.spotify/hamcrest-pojo)\n\nMany applications at Spotify are very data heavy.  They might be\naggregation services that combine a lot of data structures into even\nmore complicated data structures.  And the basic data structures are\nusually complicated to begin with.\n\nThe POJO matcher library lets you describe the structure of a POJO in\na fluent style and then match against that structure.  It's optimized\nfor very complicated objects with a lot of properties.  When a\nmismatch occurs, the library tries to minimally describe the mismatch.\n\nExample:\n\n```java\nfinal List\u003cUser\u003e users;\ntry (Stream\u003cUser\u003e userStream = sut.fetchAllUsers()) {\n  users = userStream.collect(Collectors.toList());\n}\n\nassertThat(users, contains(\n    pojo(User.class)\n        .where(\"address\", is(\n            pojo(Address.class)\n                .withProperty(\"street\", is(\"Main Street\"))\n                .withProperty(\"country\", is(\"US\"))\n        ))\n        .where(\"product\", is(\n            pojo(Product.class)\n                .withProperty(\"id\", is(1))\n                .withProperty(\"name\", is(\"premium\"))\n                .withProperty(\"metadata\", is(\"{\\\"foo\\\": [\\\"bar\\\", \\\"baz\\\"]}\"))\n                .withProperty(\"creationDate\", is(Timestamp.from(Instant.EPOCH)))\n                .withProperty(\"isTest\", is(false))\n        ))\n));\n```\n\nExample output:\n\n```\nExpected:\niterable containing [User {\n  address(): is Address {\n    getStreet(): is \"Main Street\"\n    getCountry(): is \"US\"\n  }\n  product(): is Product {\n    getId(): is \u003c1\u003e\n    getName(): is \"premium\"\n    getMetadata(): is \"{\\\"foo\\\": [\\\"bar\\\", \\\"baz\\\"]}\"\n    getCreationDate(): is \u003c1970-01-01 01:00:00.0\u003e\n    getIsTest(): is \u003cfalse\u003e\n  }\n}]\n\nbut:\nitem 0: User {\n  ...\n  product(): Product {\n    ...\n    getMetadata(): was \"{\\\"foo\\\": \\\"bar\\\"}\"\n    ...\n  }\n  ...\n}\n```\n\n### JSON matchers\n[![Javadocs](http://www.javadoc.io/badge/com.spotify/hamcrest-jackson.svg?color=blue)](http://www.javadoc.io/doc/com.spotify/hamcrest-jackson)\n\nSimilar to the POJO matchers, the JSON matchers let you describe a\nJSON structure and match against it.\n\nThe match can be on a `String` or a jackson `JsonNode`. \n\n```java\n// You can match a String\nString jsonString = \"{\" +\n \"  \\\"foo\\\": 1,\" +\n \"  \\\"bar\\\": true,\" +\n \"  \\\"baz\\\": {\" +\n \"    \\\"foo\\\": true\" +\n \"  }\" +\n \"}\"\n\n// You can match a Json String directly\nassertThat(\"{}\", isJsonStringMatching(jsonObject()));\n\n// Or match a Jackson node\nJsonNode json = new ObjectMapper().readTree(jsonString);\nassertThat(json, is(\n     jsonObject()\n         .where(\"foo\", is(jsonInt(1)))\n         .where(\"bar\", is(jsonBoolean(true)))\n         .where(\"baz\", is(\n             jsonObject()\n                 .where(\"foo\", is(jsonNull()))))));\n```\n\nA failing test would look like:\n\n```\nExpected:\n{\n  \"foo\": is a number node is \u003c1\u003e\n  \"bar\": is a boolean node is \u003cfalse\u003e\n  \"baz\": is {\n    \"foo\": is a null node\n  }\n}\n\nbut:\n{\n  ...\n  \"baz\": {\n    ...\n    \"foo\": was not a null node, but a boolean node\n    ...\n  }\n  ...\n}\n```\n\nYou can match a JSON Array by combining with existing Hamcrest collection Matchers:\n\n```java\nString jsonArrayString = \"[\"foo\", \"bar\"]\";\nJsonNode json = new ObjectMapper().readTree(jsonArrayString);\nassertThat(json, is(jsonArray(contains(jsonText(\"foo\"), jsonText(\"bar\")))));\n```\n\n### java.util.Optional matchers\n[![Javadocs](http://www.javadoc.io/badge/com.spotify/hamcrest-optional.svg?color=blue)](http://www.javadoc.io/doc/com.spotify/hamcrest-optional)\n\n`com.spotify:hamcrest-optional` provides matchers for the Java 8\nOptional type so you don't have to unpack the Optional in your tests.\n\n```java\nfinal Optional\u003cString\u003e response = methodUnderTest();\nassertThat(response, is(optionalWithValue(equalTo(\"foo\")));\n\nfinal Optional\u003cCollection\u003cFoo\u003e\u003e col = anotherMethod();\nassertThat(response, is(optionalWithValue(containsInAnyOrder(...))));\n\n// or if you only care that the Optional is non-empty:\nassertThat(response, is(optionalWithValue()));\n\n// or if you expect an empty Optional:\nassertThat(response, is(emptyOptional()));\n```\n\n### Future matchers\n[![Javadocs](http://www.javadoc.io/badge/com.spotify/hamcrest-future.svg?color=blue)](http://www.javadoc.io/doc/com.spotify/hamcrest-future)\n\nSimilar to the Optional matchers, the CompletionStage /\nCompletableFuture matchers in `com.spotify:hamcrest-future` allow\nyou to assert against the value or completion state of a\nCompletionStage without having to unpack it in your test code or\nhandle the checked exceptions of `Future.get()` (or using\n`Futures.getUnchecked(future)`).\n\nThere are four dimensions you can choose from when using Future\nmatchers:\n\n  * raw `Future` vs Java 8's `CompletableFuture`\n  * blocking vs non-blocking\n      * blocking: the matcher will wait, perhaps indefinitely, for the\n        future to complete\n      * non-blocking: the matcher will not match if the future is not\n        yet completed\n  * completed successfully vs completed with an exception\n  * match anything vs pass in another matcher\n\nSo there are a total of 16 methods you can call:\n\n#### raw `Future` matchers\n\nUse `com.spotify.hamcrest.future.FutureMatchers`:\n\n|             | blocking                                | non-blocking |\n| ----------- | --------------------------------------- | ------------ |\n| successful  | futureWillCompleteWithValue\\[That]()     | futureCompletedWithValue\\[That]() |\n| exceptional | futureWillCompleteWithException\\[That]() | futureCompletedWithException\\[That]() |\n\n#### Java 8's `CompletableFuture` matchers\n\nUse `com.spotify.hamcrest.future.CompletableFutureMatchers`:\n\n|             | blocking                               | non-blocking |\n| ----------- | -------------------------------------- | ------------ |\n| successful  | stageWillCompleteWithValue\\[That]()     | stageCompletedWithValue\\[That]() |\n| exceptional | stageWillCompleteWithException\\[That]() | stageCompletedWithException\\[That]() |\n\nNote that to test that a CompletionStage completed with a certain\nvalue or exception use `..That(..)`.\n\n```java\nCompletionStage\u003cList\u003cFoo\u003e\u003e f = someMethod();\nassertThat(f, stageCompletedWithValueThat(contains(...));\n\nCompletionStage\u003cFoo\u003e c = methodThatShouldFail();\nassertThat(c, stageCompletedWithExceptionThat(isA(FooException.class)));\n```\n\nIf you want the matcher to block until the CompletionStage is\ncompleted, use `stageWillCompleteWithValueThat(..)`:\n\n```java\n// warning: might block forever if the stage never completes!\nCompletionStage\u003cList\u003cFoo\u003e\u003e f = someMethod();\nassertThat(f, stageWillCompleteWithValueThat(is(equalTo(...)));\n```\n\nBe careful when using this matcher as it might block forever if the\nstage never completes! Consider restructuring your tests so that the\ncompletions returned from the method/class being tested are\nimmediately completed (e.g. using MoreExecutors.directExecutor, etc).\n\n\n## Prerequisities\n\nAny platform that has the following\n\n* Java 8+\n* Maven 3 (for compiling)\n\n\n## Releasing\n\nThis plugin is uploaded to Maven Central via the Maven release plugin. You'll need\ncredentials for Spotify's Sonatype account in your `~/.m2/settings.xml` as well as a GPG key to\nsign the artifacts.\n\n```\nmvn -Dgpg.keyname=\u003cKEY-ID\u003e release:prepare release:perform\n```\n\n\n## Code of conduct\n\nThis project adheres to the [Open Code of Conduct][code-of-conduct]. By participating, you are\nexpected to honor this code.\n\n  [code-of-conduct]: https://github.com/spotify/code-of-conduct/blob/master/code-of-conduct.md\n  [maven-search]: https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.spotify%22%20hamcrest*\n\n## Ownership\n\nThe Weaver squad is currently owning this project internally.\nWe are currently in the evaluating process of the ownership of this and other OSS Java libraries.\nThe ownership takes into account **ONLY** security maintenance.\n\nThis repo is also co-owned by other people:\n\n* [mattnworb](https://github.com/mattnworb)","funding_links":[],"categories":["测试"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspotify%2Fjava-hamcrest","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fspotify%2Fjava-hamcrest","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspotify%2Fjava-hamcrest/lists"}