- Notifications
You must be signed in to change notification settings - Fork8
An assertions framework for .NET with a BDD-like feel, inspired by Chai and Jasmine, designed to be user-extensible
License
fluffynuts/NExpect
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
An assertions framework for .NET with a BDD-like feel, inspired by Chai and Jasmine, designed to be user-extensible
- Expect(NExpect).To.Be.Readable();
- Because code is for co-workers, not compilers. And your tests are part of your documentation.
- Expect(NExpect).To.Be.Expressive();
- Because the intent of a test should be easy to understand. The reader can delve into the details when she cares to.
- Expect(NExpect).To.Be.Extensible();
- Because I can't predict every use-case. I believe that your assertions framework should enable expressive, readable tests through extension.
https://fluffynuts.github.io/NExpectdev.to
- Download fromnuget.org:
install-package nexpect
- Import Expectations statically:
usingstaticNExpect.Expectations;
Expect
inside your tests, with fluent syntax:
// simple equality checksExpect(1).To.Equal(1);Expect(true).To.Not.Be.False();// alt. grammarExpect(null).To.Be.Null();// - with negation, order doesn't matterExpect("moo").Not.To.Equal("cow");Expect("moo").To.Not.Equal("cow");Expect(true).Not.To.Be.False();Expect(false).To.Not.Be.True();// exceptionsExpect(()=>{}).Not.To.Throw();Expect(()=>{thrownewArgumentException("moo","moo cow");}).To.Throw<ArgumentException>().With.Message.Containing("moo").And.("cow");// smarter string tests, with fluencyExpect(someString).To.Contain("moo").And("cow");Expect("moo, said the cow").To.Start.With("moo").And.Contain("said").Then("the").And.End.With("cow");// collection testsExpect(someCollection).To.Contain.Exactly(2).Matched.By(item=>item.IsWhatWeWant());Expect(someCollection).To.Contain.Only(1).Deep.Equal.To(new{id=42,name="Douglas"});Expect(someFlags).To.Contain.At.Least(3).Equal.To(true);Expect(new[]{1,2,3}).To.Be.Ordered.Ascending();Expect(new[]{"c","b","a"}).To.Be.Ordered.Descending();// type testingExpect(someObject).To.Be.An.Instance.Of<Cow>();// deep and intersection equality testingvarperson=new{id=1,name="bob"};Expect(person).To.Deep.Equal(new{id=1,name="bob"});Expect(person).To.Intersection.Equal(new{name="bob"});// deep equality testing with excluded propsExpect(person).To.Deep.Equal(new{id=1,name="sarah"},exclude:["name"]);// orExpect(person).Omitting("name").To.Deep.Equal(new{id=1,name="sipho"});
Mostly, you can extend by adding extension methods for ICanAddMatcher where T is thetype you want. You can also extend at any point in the grammar -- some of the "better"points are ITo, IBe, IHave, IA, IAn. You will need another namespace import:
usingNExpect.MatcherLogic
And your extension methods can be like:
publicstaticclassMyMatchers{publicstaticvoidFive(thisIBe<int>continuation){continuation.AddMatcher(actual=>{varpassed=actual==5;varmessage=passed?$"Expected{actual} not to be 5":$"Expected{actual} to be 5";returnnewMatcherResult(passed,message);});}}
// somewhere else...[Test]publicvoidFifteenDividedByThree_ShouldEqual_Five(){varresult=15/3;Expect(result).To.Be.Five();}// Yes, yes, simple example is simple.
If you've ever written a Jasmine matcher, this should feel familiar.
If you have a bunch of existing expectations that you'd like to wrapup into a nicely-named matcher,.Compose
has you covered:
// beforevarcow=animalFactory.MakeCow();varbeetle=animalFactory.MakeBeetle();// animal factory should make a Jersey cowExpect(cow.Classification).To.Equal("Mammal");Expect(cow.Legs).To.Equal(4);Expect(cow.HasTail).To.Be.True();Expect(cow.HasHorns).To.Be.True();Expect(cow.HasSpots).To.Be.True();// Animal factory should make a rhinoceros beetleExpect(beetle.Classification).To.Equal("Insect");Expect(beetle.Legs).To.Equal(6);Expect(beetle.HasTail).To.Be.False();Expect(beetle.HasHorns).To.Be.True();Expect(beetle.HasSpots).To.Be.False();
// aftervarcow=animalFactory.MakeJerseyCow();varbeetle=animalFactory.MakeRhinocerosBeetle();Expect(cow).To.Be.A.JerseyCow();Expect(beetle).To.Be.A.RhinocerosBeetle();// elsewhere:publicstaticclassAnimalMatchers{// the IMore<T> interface allows fluent chaining of expectations// eg:// Expect(cow).To.Be.A.JerseyCow()// .And// .Not.To.Be.A.FrieslandCow();publicstaticIMore<Animal>JerseyCow(thisIA<Animal>a){returna.Compose(actual=>{Expect(cow.Classification).To.Equal("Mammal");Expect(cow.Legs).To.Equal(4);Expect(cow.HasTail).To.Be.True();Expect(cow.HasHorns).To.Be.True();Expect(cow.HasSpots).To.Be.True();});}publicstaticIMore<Animal>RhinocerosBeetle(thisIA<Animal>a){returna.Compose(actual=>{Expect(beetle.Classification).To.Equal("Insect");Expect(beetle.Legs).To.Equal(6);Expect(beetle.HasTail).To.Be.False();Expect(beetle.HasHorns).To.Be.True();Expect(beetle.HasSpots).To.Be.False();});}}
When one of the inner expectations fails, NExpect attempts to constructa nice failure message. As with all expectations, you can always makefailures easier to understand with a custom message string or generator:
usingNExpect.Implementations;usingNExpect.MatcherLogic;usingNExpect;usingstaticNExpect.Expectations;publicstaticclassAnimalMatchers{publicstaticIMore<Animal>JerseyCow(thisIA<Animal>a){returna.Compose(actual=>{// the Stringify extension method, available on all types,// comes from NExpect.Implementation.MessageHelpers and// produces a string representation of the object it's// operating on which is similar to JSON, so it's easier// to read what the object wasvarcustomMessage=$"Expected{actual.Stringify()} to be a cow";Expect(cow.Classification).To.Equal("Mammal",customMessage);Expect(cow.Legs).To.Equal(4,customMessage);Expect(cow.HasTail).To.Be.True(customMessage);Expect(cow.HasHorns).To.Be.True(customMessage);Expect(cow.HasSpots).To.Be.True(customMessage);});}publicstaticIMore<Animal>RhinocerosBeetle(thisIA<Animal>a){returna.Compose(actual=>{// we can use a generator func to delay generation of the message// which is especially helpful if message generation is expensive// and we'd only like to spend that cpu time on a failureFunc<string>customMessageGenerator=()=>$"Expected{actual.Stringify()} to be a cow";Expect(beetle.Classification).To.Equal("Insect",customMessageGenerator);Expect(beetle.Legs).To.Equal(6,customMessageGenerator);Expect(beetle.HasTail).To.Be.False(customMessageGenerator);Expect(beetle.HasHorns).To.Be.True(customMessageGenerator);Expect(beetle.HasSpots).To.Be.False(customMessageGenerator);});}}
About
An assertions framework for .NET with a BDD-like feel, inspired by Chai and Jasmine, designed to be user-extensible
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
Uh oh!
There was an error while loading.Please reload this page.
Contributors7
Uh oh!
There was an error while loading.Please reload this page.