{"id":15598788,"url":"https://github.com/fluffynuts/nexpect","last_synced_at":"2025-06-23T09:32:35.598Z","repository":{"id":37706278,"uuid":"96705595","full_name":"fluffynuts/NExpect","owner":"fluffynuts","description":"An assertions framework for .NET with a BDD-like feel, inspired by Chai and Jasmine, designed to be user-extensible","archived":false,"fork":false,"pushed_at":"2025-04-04T11:18:36.000Z","size":3341,"stargazers_count":23,"open_issues_count":0,"forks_count":8,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-06-22T14:23:09.751Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fluffynuts.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":"2017-07-09T19:11:43.000Z","updated_at":"2025-04-04T11:18:39.000Z","dependencies_parsed_at":"2024-03-11T15:54:25.024Z","dependency_job_id":"83577816-f5fb-4175-89ac-938e0da2e662","html_url":"https://github.com/fluffynuts/NExpect","commit_stats":{"total_commits":811,"total_committers":8,"mean_commits":101.375,"dds":0.04932182490752157,"last_synced_commit":"efe5f492d693b4fad8703c45817dee3954d1594a"},"previous_names":[],"tags_count":254,"template":false,"template_full_name":null,"purl":"pkg:github/fluffynuts/NExpect","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluffynuts%2FNExpect","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluffynuts%2FNExpect/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluffynuts%2FNExpect/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluffynuts%2FNExpect/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fluffynuts","download_url":"https://codeload.github.com/fluffynuts/NExpect/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluffynuts%2FNExpect/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261452908,"owners_count":23160415,"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-03T01:41:19.301Z","updated_at":"2025-06-23T09:32:30.580Z","avatar_url":"https://github.com/fluffynuts.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# NExpect\nAn assertions framework for .NET with a BDD-like feel, inspired by Chai and Jasmine, designed to be user-extensible\n\n![Build and Test](https://github.com/fluffynuts/NExpect/workflows/Build%20and%20Test/badge.svg)\n\n![Nuget current version badge](https://img.shields.io/nuget/v/NExpect)\n\n## Goals\n- Expect(NExpect).To.Be.Readable();\n  - Because code is for co-workers, not compilers. And your tests are part of your documentation.\n- Expect(NExpect).To.Be.Expressive();\n  - Because the intent of a test should be easy to understand. The reader can delve into the details when she cares to.\n- Expect(NExpect).To.Be.Extensible();\n  - Because I can't predict every use-case. I believe that your assertions framework should enable expressive, readable tests through extension.\n\n## Tutorial / blog posts:\n[https://fluffynuts.github.io/NExpect](https://fluffynuts.github.io/NExpect)\n[dev.to](https://dev.to/fluffynuts/introducing-nexpect-555c)\n\n## Usage\n1. Download from [nuget.org](https://nuget.org): `install-package nexpect`\n2. Import Expectations statically:\n```csharp\nusing static NExpect.Expectations;\n```\n3. `Expect` inside your tests, with fluent syntax:\n```csharp\n// simple equality checks\nExpect(1).To.Equal(1);\nExpect(true).To.Not.Be.False(); // alt. grammar\nExpect(null).To.Be.Null();\n// - with negation, order doesn't matter\nExpect(\"moo\").Not.To.Equal(\"cow\");\nExpect(\"moo\").To.Not.Equal(\"cow\");\nExpect(true).Not.To.Be.False();\nExpect(false).To.Not.Be.True();\n\n// exceptions\nExpect(() =\u003e { }).Not.To.Throw();\nExpect(() =\u003e\n  {\n    throw new ArgumentException(\"moo\", \"moo cow\");\n  }).To.Throw\u003cArgumentException\u003e()\n  .With.Message.Containing(\"moo\")\n  .And.(\"cow\");\n\n// smarter string tests, with fluency\nExpect(someString).To.Contain(\"moo\").And(\"cow\");\nExpect(\"moo, said the cow\")\n    .To.Start.With(\"moo\")\n    .And.Contain(\"said\")\n    .Then(\"the\")\n    .And.End.With(\"cow\");\n\n// collection tests\nExpect(someCollection).To.Contain.Exactly(2)\n  .Matched.By(item =\u003e item.IsWhatWeWant());\nExpect(someCollection).To.Contain.Only(1)\n  .Deep.Equal.To(new { id = 42, name = \"Douglas\" });\nExpect(someFlags).To.Contain.At.Least(3)\n  .Equal.To(true);\nExpect(new[] { 1, 2, 3 })\n  .To.Be.Ordered.Ascending();\nExpect(new[] { \"c\", \"b\", \"a\" })\n  .To.Be.Ordered.Descending();\n\n// type testing\nExpect(someObject).To.Be\n  .An.Instance.Of\u003cCow\u003e();\n\n// deep and intersection equality testing\nvar person = new {\n  id = 1,\n  name = \"bob\"\n};\nExpect(person)\n  .To.Deep.Equal(new { id = 1, name = \"bob\" });\nExpect(person)\n  .To.Intersection.Equal(new { name = \"bob\" });\n```\n\n## Extending\nMostly, you can extend by adding extension methods for ICanAddMatcher\u003cT\u003e where T is the\ntype you want. You can also extend at any point in the grammar -- some of the \"better\"\npoints are ITo\u003cT\u003e, IBe\u003cT\u003e, IHave\u003cT\u003e, IA\u003cT\u003e, IAn\u003cT\u003e. You will need another namespace import:\n```csharp\nusing NExpect.MatcherLogic\n```\nAnd your extension methods can be like:\n\n```csharp\npublic static class MyMatchers\n{\n  public static void Five(this IBe\u003cint\u003e continuation)\n  {\n    continuation.AddMatcher(actual =\u003e\n    {\n      var passed = actual == 5;\n      var message = passed\n                    ? $\"Expected {actual} not to be 5\"\n                    : $\"Expected {actual} to be 5\";\n      return new MatcherResult(passed, message);\n    });\n  }\n}\n```\n\n```csharp\n// somewhere else...\n[Test]\npublic void FifteenDividedByThree_ShouldEqual_Five()\n{\n  var result = 15 / 3;\n  Expect(result).To.Be.Five();\n}\n// Yes, yes, simple example is simple.\n```\n\nIf you've ever written a Jasmine matcher, this should feel familiar.\n\nIf you have a bunch of existing expectations that you'd like to wrap\nup into a nicely-named matcher, `.Compose` has you covered:\n\n```csharp\n// before\nvar cow = animalFactory.MakeCow();\nvar beetle = animalFactory.MakeBeetle();\n\n// animal factory should make a Jersey cow\nExpect(cow.Classification).To.Equal(\"Mammal\");\nExpect(cow.Legs).To.Equal(4);\nExpect(cow.HasTail).To.Be.True();\nExpect(cow.HasHorns).To.Be.True();\nExpect(cow.HasSpots).To.Be.True();\n\n// Animal factory should make a rhinoceros beetle\nExpect(beetle.Classification).To.Equal(\"Insect\");\nExpect(beetle.Legs).To.Equal(6);\nExpect(beetle.HasTail).To.Be.False();\nExpect(beetle.HasHorns).To.Be.True();\nExpect(beetle.HasSpots).To.Be.False();\n```\n\n```csharp\n// after\nvar cow = animalFactory.MakeJerseyCow();\nvar beetle = animalFactory.MakeRhinocerosBeetle();\n\nExpect(cow).To.Be.A.JerseyCow();\nExpect(beetle).To.Be.A.RhinocerosBeetle();\n\n\n// elsewhere:\n\npublic static class AnimalMatchers\n{\n  // the IMore\u003cT\u003e interface allows fluent chaining of expectations\n  //  eg:\n  //  Expect(cow).To.Be.A.JerseyCow()\n  //     .And\n  //     .Not.To.Be.A.FrieslandCow();\n  public static IMore\u003cAnimal\u003e JerseyCow(this IA\u003cAnimal\u003e a)\n  {\n    return a.Compose(actual =\u003e\n    {\n      Expect(cow.Classification).To.Equal(\"Mammal\");\n      Expect(cow.Legs).To.Equal(4);\n      Expect(cow.HasTail).To.Be.True();\n      Expect(cow.HasHorns).To.Be.True();\n      Expect(cow.HasSpots).To.Be.True();\n    });\n  }\n  public static IMore\u003cAnimal\u003e RhinocerosBeetle(this IA\u003cAnimal\u003e a)\n  {\n    return a.Compose(actual =\u003e\n    {\n      Expect(beetle.Classification).To.Equal(\"Insect\");\n      Expect(beetle.Legs).To.Equal(6);\n      Expect(beetle.HasTail).To.Be.False();\n      Expect(beetle.HasHorns).To.Be.True();\n      Expect(beetle.HasSpots).To.Be.False();\n    });\n  }\n}\n```\n\nWhen one of the inner expectations fails, NExpect attempts to construct\na nice failure message. As with all expectations, you can always make\nfailures easier to understand with a custom message string or generator:\n\n```csharp\nusing NExpect.Implementations;\nusing NExpect.MatcherLogic;\nusing NExpect;\nusing static NExpect.Expectations;\n\npublic static class AnimalMatchers\n{\n  public static IMore\u003cAnimal\u003e JerseyCow(this IA\u003cAnimal\u003e a)\n  {\n    return a.Compose(actual =\u003e\n    {\n      // the Stringify extension method, available on all types,\n      // comes from NExpect.Implementation.MessageHelpers and\n      // produces a string representation of the object it's\n      // operating on which is similar to JSON, so it's easier\n      // to read what the object was\n      var customMessage = $\"Expected {actual.Stringify()} to be a cow\";\n      Expect(cow.Classification).To.Equal(\"Mammal\", customMessage);\n      Expect(cow.Legs).To.Equal(4, customMessage);\n      Expect(cow.HasTail).To.Be.True(customMessage);\n      Expect(cow.HasHorns).To.Be.True(customMessage);\n      Expect(cow.HasSpots).To.Be.True(customMessage);\n    });\n  }\n  public static IMore\u003cAnimal\u003e RhinocerosBeetle(this IA\u003cAnimal\u003e a)\n  {\n    return a.Compose(actual =\u003e\n    {\n      // we can use a generator func to delay generation of the message\n      //  which is especially helpful if message generation is expensive\n      //  and we'd only like to spend that cpu time on a failure\n      Func\u003cstring\u003e customMessageGenerator = () =\u003e $\"Expected {actual.Stringify()} to be a cow\";\n      Expect(beetle.Classification).To.Equal(\"Insect\", customMessageGenerator);\n      Expect(beetle.Legs).To.Equal(6, customMessageGenerator);\n      Expect(beetle.HasTail).To.Be.False(customMessageGenerator);\n      Expect(beetle.HasHorns).To.Be.True(customMessageGenerator);\n      Expect(beetle.HasSpots).To.Be.False(customMessageGenerator);\n    });\n  }\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffluffynuts%2Fnexpect","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffluffynuts%2Fnexpect","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffluffynuts%2Fnexpect/lists"}