<commit_before>
Summary
============

Testing library providing a fluent tdd/bdd testing approach. Can be easily integrated 
into your own testing tools (nunit, xunit, moq, etc)

The driving concepts behind this library are:

Comprehension
------------

    * tests should be easy to understand. Tests are read far more often than they are written. Focus on the read part
    * if possible make tests easy to write too. Easy to write tests result in more test code and more fun
    * keep tests as close to natural language as possible as this is quicker to parse, though try to eliminate ambiguity

Making the IDE work for you
------------
   
    * support autocomplete.
    * support refactoring.
    * make it easy to jump directly to code doing the actual work.

Integration
------------

    * easily integrate with existing test infrastructure

Extensibility
------------
        
    * make it easy to customise your tests.
    * infrastructure should aid you not hinder.
    * allow you to do your own thing when required. Replace the bits you need without having to reimplement all the parts
    * not force you to do it a certain way, though following conventions helps.

Discoverability
------------

    * discovery of things should be easy without the need to go and read the documentation. 
    * a consistent and easy to guess naming pattern.

Diagnostics
------------

If a test fails tell explain why and provide as much info as possible why it failed. Don't tell me foo is wrong, 
tell me why and what was expected and what was actually found, and any other related info.

DRY
------------

Don't repeat the same boring string assertion, or complex relationship tests across all your tests. Put it 
in a single place (your Matcher).

For example, the scenario:

    "Given a registered user, with an account balance of 10 dollars, when 6 dollars is debited, then 
    expect that the account only has 4 dollars, and the transaction ledger records a 6 dollar debit"

can be written in TestFirst.Net as:

    `Scenario()
        .Given(user = UserInTheDb().WithDefaults())
        .Given(account = AccountInTheDb().For(user).Balance(10).Dollars())
        
        .When(()=>account.debit(6))

        .Then(
            ExpectThat(TheAccountInTheDb.For(account)),
            Is(AnAcccount.With().Balance(4).Dollars())
        .Then(
            ExpectThat(TheAccountLedgerInTheDb.For(account)),
            Is(AnLedger.With().Debit(6).Dollars());`
    
Which depending on the number of beers you've drunk resembles the natural english version fairly closely without the need of an additional
template translation step in the process (so refactoring won't kill things, find references still work, can step directly to the assertion code)    

Matchers
============

TestFirst.Net centers around the concept of a 'Matcher'. This is a class separate from your individual unit test to perform assertions
on the objects and services under test. Naming convention is that matchers names start with an 'A' or an 'An'

Examples:

    `AString.Contains(...)
    AnInt.Between(2,5)
    ADateTime.Now().Within(3).Seconds()
    ACookie.With().Name("foo").Value(AString.MatchingAndPattern("?bar*)).Expires(ADateTime.After(DateTime.Now)));
    AFoo.With().Bar("123").Fibble(AFibble.With().BigEars().NoMoustache());`

The idea is that as you flesh out your tests over time, more and more of the test code can be reused. This is
versus all the assertions repeated in your test. So for example if there is a concept of a 'valid' email address, 
there can be an email address matcher, or in combination with your user matcher you can call:

    AUser.With().ValidEmail() under the hood might call 'AnEmailAddress.IsValid(...)'

Ditto for things like a valid user account, trade, registration etc

As more and more matchers are added over time, more of your tests can be written using existing matchers. If some
concept changes, in theory only a few locations in your test code need to also.

Remember, auto complete is your friend! If you stick to the naming conventions, you only need to start typing 
and in theory completions should come up. 

The static create method is usually 'With' for complex matchers, or simply the matcher method for simpler 
ones. Sometimes 'Of' or 'For' are used if this aids in the fluent langauge

There are basic matchers for most of the primitive types, along for other base types. Simply hit 'A' and start typing. 
Some existing ones are 'AString', 'AnInt', 'ADecimal', 'ADateTime', 'AList','ADictionary', 'AnInstance'. Others are 
for you to write for your own objects. The neat thing is this can then be reused across tests. 

There is a code generator to generate matchers automatically for each of your objects.

Usage
============

Using just the assertions
----------

This is useful if you only want to make use of the matchers and/or sprinkle your existing tests with a bit of TestFirst.Net

Examples:

    ...do stuff in your test

    Expect
        .That(foolist) <--thing we want to assert
        .Is(AList.InAnyOrder().WithOnly("a").And("b")); <--'Matcher' we are using to perform the 

    Expect
        .That(()=>foo.DoIt())
        .Throws(AnException.Of().Type<MyException>().Message(AString.ContainingIgnorePunctuationAndCase("Some bad thing")));
    
    Expect
        .That(()=>foo.map())
        .Is(ADictionary
            .KeyMatching("a","value_a")
            .KeyMatching("foo",AFoo.With().FloppyEars().SunHat()));

Scenario based
----------

Setup scenarios which provide injection, db creation, db insertion and retrieval, service startup, resource cleanup. 

You can still roll it as you wish by combining or swapping out the parts yourself. This still integrates with your existing test classes.

If extending fo NUnit or Moq, include nuget package TestFirst.Net.Extensions

[TestFixture]
MyTestScenario : AbstractNUnitScenarioTest {...//or AbstractNUnitMoqScenarioTest or ScenarioFluency

    [Test]
    public void HappyPathUserCorrectlyRegistered(){
        RegistrationService service;
        Registration reg;            

        Scenario() <-- passes back a 'Scenario' object with an injector
            .Given(reg = UserRegistration.With().Defaults().Age(123).RandomPassword()..)
            .Given(service = NewRegistrationService())    <--this is disposed at end of test
            .When(service.register(reg))//<!--interesting part of test
            .Then(
                ExpectThat(UserInTheDb.With().UserName(reg.UserName)), <-- UserInTheDb is a 'Fetcher'
                Is(AUserInTheDb.With().Age(reg.Age)...))
            .Then(
                ExpectThat(LoginInTheDb.With().UserName(reg.UserName)),
                Is(ALoginInTheDb.With().Password(reg.Password)...))
            .Then(
                ExpectThat(AccountInTheDb.With().UserName(reg.UserName)),
                Is(AnAccount.With().Created(ADateTime.After(now)...))

    }
}

Test now clearly shows the setup, the operation(s) we're testing, and the expected result

The 'XInTheDb', as in 'UserInTheDb' implements the 'IFetcher' interface. This simply is used to look things up (how you do it 
up to you). It will also have dependencies injected. Up to you to write or generate this class.

The 'Given', 'When', 'Then' methods are chained builder methods taking in a number of different parameter types. All objects
passed in have their dependencies set via the IStepArgDependencyInjector. The default setup simply
collects all objects implementing 'IDisposable' and disposes of them in reverse order on test method exit.

To customise the scenario, call the various 'UseX...' methods before creating the scenario, as in:

    UseScenarioInjector(myInjector);

    Scenario()
        ...

For custom injection for all tests simply create your own base test case which sets the various options in the call to 'Scenario',<commit_msg>more markdown updates<commit_after>
Summary
============

Testing library providing a fluent tdd/bdd testing approach. Can be easily integrated 
into your own testing tools (nunit, xunit, moq, etc)

The driving concepts behind this library are:

Comprehension
------------

* tests should be easy to understand. Since code is read far more than written, focus on the read part.
* keep tests as close to natural language as possible, though try to eliminate ambiguity
* if possible also make tests easy to write. This results in more test code and more fun

Making the IDE work for you
------------
   
* support autocomplete.
* support refactoring.
* make it easy to jump directly to code doing the actual work.

Integration
------------

* easily integrate with existing test infrastructure

Extensibility
------------
        
* make it easy to customise your tests.
* infrastructure should aid not hinder.
* allow you to do your own thing when required. Replace the bits you need without having to reimplement all the parts
* not force you to do it a certain way, though following conventions helps.

Discoverability
------------

* discovery of things should be easy without the need to go and read the documentation. 
* a consistent and easy to guess naming pattern.

Diagnostics
------------

If a test fails tell explain why and provide as much info as possible why it failed. Don't tell me foo is wrong, 
tell me why and what was expected and what was actually found, and any other related info.

DRY
------------

Don't repeat the same boring string assertion, or complex relationship tests across all your tests. Put it 
in a single place (your Matcher).

Example
------------

The scenario:

    "Given a registered user, with an account balance of 10 dollars, when 6 dollars is debited, then 
    expect that the account only has 4 dollars, and the transaction ledger records a 6 dollar debit"

can be written in TestFirst.Net as:

    Scenario()
        .Given(user = UserInTheDb().WithDefaults())
        .Given(account = AccountInTheDb().For(user).Balance(10).Dollars())
        
        .When(()=>account.debit(6))

        .Then(
            ExpectThat(TheAccountInTheDb.For(account)),
            Is(AnAcccount.With().Balance(4).Dollars())
        .Then(
            ExpectThat(TheAccountLedgerInTheDb.For(account)),
            Is(AnLedger.With().Debit(6).Dollars());
    
Which depending on the number of beers you've drunk resembles the natural english version fairly closely without the need of an additional
template translation step in the process (so refactoring won't kill things, find references still work, can step directly to the assertion code)    

Matchers
============

TestFirst.Net centers around the concept of a 'Matcher'. This is a class separate from your individual unit test to perform assertions
on the objects and services under test. Naming convention is that matchers names start with an 'A' or an 'An'

Examples:

    AString.Contains(...)
    AnInt.Between(2,5)
    ADateTime.Now().Within(3).Seconds()
    ACookie.With().Name("foo").Value(AString.MatchingAndPattern("?bar*)).Expires(ADateTime.After(DateTime.Now)));
    AFoo.With().Bar("123").Fibble(AFibble.With().BigEars().NoMoustache());

The idea is that as you flesh out your tests over time, more and more of the test code can be reused. This is
versus all the assertions repeated in your test. So for example if there is a concept of a 'valid' email address, 
there can be an email address matcher, or in combination with your user matcher you can call:

    AUser.With().ValidEmail() under the hood might call 'AnEmailAddress.IsValid(...)'

Ditto for things like a valid user account, trade, registration etc

As more and more matchers are added over time, more of your tests can be written using existing matchers. If some
concept changes, in theory only a few locations in your test code need to also.

Remember, auto complete is your friend! If you stick to the naming conventions, you only need to start typing 
and in theory completions should come up. 

The static create method is usually 'With' for complex matchers, or simply the matcher method for simpler 
ones. Sometimes 'Of' or 'For' are used if this aids in the fluent langauge

There are basic matchers for most of the primitive types, along for other base types. Simply hit 'A' and start typing. 
Some existing ones are 'AString', 'AnInt', 'ADecimal', 'ADateTime', 'AList','ADictionary', 'AnInstance'. Others are 
for you to write for your own objects. The neat thing is this can then be reused across tests. 

There is a code generator to generate matchers automatically for each of your objects.

Usage
============

Using just the assertions
----------

This is useful if you only want to make use of the matchers and/or sprinkle your existing tests with a bit of TestFirst.Net

Examples:

    ...do stuff in your test

    Expect
        .That(foolist) <--thing we want to assert
        .Is(AList.InAnyOrder().WithOnly("a").And("b")); <--'Matcher' we are using to perform the 

    Expect
        .That(()=>foo.DoIt())
        .Throws(AnException.Of().Type<MyException>().Message(AString.ContainingIgnorePunctuationAndCase("Some bad thing")));
    
    Expect
        .That(()=>foo.map())
        .Is(ADictionary
            .KeyMatching("a","value_a")
            .KeyMatching("foo",AFoo.With().FloppyEars().SunHat()));

Scenario based
----------
Setup scenarios which provide injection, db creation, db insertion and retrieval, service startup, resource cleanup. 

You can still roll it as you wish by combining or swapping out the parts yourself. This still integrates with your existing test classes.

If extending fo NUnit or Moq, include nuget package TestFirst.Net.Extensions

    [TestFixture]
    MyTestScenario : AbstractNUnitScenarioTest {...//or AbstractNUnitMoqScenarioTest or ScenarioFluency

        [Test]
        public void HappyPathUserCorrectlyRegistered(){
            RegistrationService service;
            Registration reg;            

            Scenario() <-- passes back a 'Scenario' object with an injector
                .Given(reg = UserRegistration.With().Defaults().Age(123).RandomPassword()..)
                .Given(service = NewRegistrationService())    <--this is disposed at end of test
                .When(service.register(reg))//<!--interesting part of test
                .Then(
                    ExpectThat(UserInTheDb.With().UserName(reg.UserName)), <-- UserInTheDb is a 'Fetcher'
                    Is(AUserInTheDb.With().Age(reg.Age)...))
                .Then(
                    ExpectThat(LoginInTheDb.With().UserName(reg.UserName)),
                    Is(ALoginInTheDb.With().Password(reg.Password)...))
                .Then(
                    ExpectThat(AccountInTheDb.With().UserName(reg.UserName)),
                    Is(AnAccount.With().Created(ADateTime.After(now)...))

        }
    }

Test now clearly shows the setup, the operation(s) we're testing, and the expected result

The 'XInTheDb', as in 'UserInTheDb' implements the 'IFetcher' interface. This simply is used to look things up (how you do it 
up to you). It will also have dependencies injected. Up to you to write or generate this class.

The 'Given', 'When', 'Then' methods are chained builder methods taking in a number of different parameter types. All objects
passed in have their dependencies set via the IStepArgDependencyInjector. The default setup simply
collects all objects implementing 'IDisposable' and disposes of them in reverse order on test method exit.

To customise the scenario, call the various 'UseX...' methods before creating the scenario, as in:

    UseScenarioInjector(myInjector);

    Scenario()
        ...

For custom injection for all tests simply create your own base test case which sets the various options in the call to 'Scenario',
{'fraction_non_alphanumeric': 0.09375198223913733, 'fraction_numerical': 0.0024104027909927052, 'mean_word_length': 3.1764238410596026, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3154690', 'n_tokens_mistral': 4215, 'n_tokens_neox': 4026, 'n_words': 1884}