Click here to Skip to main content
15,886,080 members
Articles / All Topics

Aubergine .NET BDD: Support for named/typed Parameters + RECURSIVE DSL + Bugfix

Rate me:
Please Sign up or sign in to vote.
0.00/5 (No votes)
11 Nov 2009CPOL 6.6K   3  
Aubergine .NET BDD: Support for named/typed Parameters + RECURSIVE DSL + bugfix

Ok, I had some ideas this morning when I woke up, so I quickly implemented them.

Changes

Here is the change_log for the new version:

  • Bugfix given a DSL attribute without a parameter is called
  • DSL definition changed to named parameters/typeconverters

Example

This has simplified the more complicated DSL definitions a LOT; check out the new definition for the AccountContext:

C#
internal class AccountContext
{
    public Account AccountA = new Account();
    public Account AccountB = new Account();
    public Exception WhenException;

    [DSL(@"(?<account>Account[AB])_has_(?<amount>\d+)_m")]
    void accountX_has_Ym(Account account, decimal amount)
    {
        account.Balance = amount * 1m;
    }

    [DSL(@"it_should_have_(?<amount>\d+)_m_on_(?<account>Account[AB])")]
    void should_have_Xm_on_AccountY(Account account, decimal amount)
    {
        account.Balance.ShouldEqual(amount * 1m);
    }

    [DSL(@"transfering_(?<amount>\d+)_m_from_(?<from>Account[AB])_to_(?<to>Account[AB])")]
    void transfering_xm_from_a_to_b(decimal amount, Account from, Account to)
    {
        from.Transfer(amount * 1m, to);
    }

    [DSL(@"the_current_user_is_authenticated_for_(?<account>Account[AB])")]
    void authenticate_for_account_x(Account account)
    {
        account.IsAuthenticated = true;
    }

    [DSL]
    void it_should_fail_with_error()
    {
      (WhenException != null).ShouldEqual(true);
    }

    [DSL("(?<name>Account[AB])")]
    Account getaccountAB(string name)
    {
        return this.Get<Account>(name);
    }
}

Note the support for typed parameters and also DSL type converters. Due to the implication, the expressiveness has changed a lot: you can now do recursive dsl definitions !!! I'll get into this when I have more time, but really short: when you call a DSL function, the input string is pushed again to the interpreter. In theory, you could define a complete language like this !!!

In the example above, [DSL(@"the_current_user_is_authenticated_for_(?<account>Account[AB])")] is called, and the result for the group <account> is again pushed into the DSL engine; if a match is found, it is called, and the result of the function is returned; if not, it tries to do a Convert.ChangeyType(xxx,destintationtype);

Finally, for reference the Story as well as the output test results:

C#
class Transfer_money_between_accounts : Story<accountcontext>
{
    As_a user;
    I_want to_transfer_money_between_accounts;
    So_that I_can_have_real_use_for_my_money;

    Given AccountA_has_3_m;
    Given AccountB_has_2_m;

    [Cols("xx", "yy", "zz")]
    [Data(1, 2, 3)]
    [Data(2, 1, 4)]
    [Data(3, 0, 5)]
    class Transfer_xx_m_between_2_accounts : Scenario
    {
        Given the_current_user_is_authenticated_for_AccountA;
        When transfering_xx_m_from_AccountA_to_AccountB;
        Then it_should_have_yy_m_on_AccountA;
        Then it_should_have_zz_m_on_AccountB;
    }

    class Transfer_too_much : Scenario
    {
        Given the_current_user_is_authenticated_for_AccountA;
        When transfering_4_m_from_AccountA_to_AccountB;
        Then it_should_have_3_m_on_AccountA;
        Then it_should_have_2_m_on_AccountB;
        Then it_should_fail_with_error;
    }

    class Not_authorized_for_transfer : Scenario
    {
        When transfering_1_m_from_AccountB_to_AccountA;
        Then it_should_have_3_m_on_AccountA;
        Then it_should_have_2_m_on_AccountB;
        Then it_should_fail_with_error;
    }
}

Output

==STORY================================================================
   Transfer_money_between_accounts => OK
   Transfer_1_m_between_2_accounts => OK
      Given AccountA_has_3_m => OK
      Given AccountB_has_2_m => OK
      Given the_current_user_is_authenticated_for_AccountA => OK
      When transfering_1_m_from_AccountA_to_AccountB => OK
      Then it_should_have_2_m_on_AccountA => OK
      Then it_should_have_3_m_on_AccountB => OK
   Transfer_2_m_between_2_accounts => OK
      Given AccountA_has_3_m => OK
      Given AccountB_has_2_m => OK
      Given the_current_user_is_authenticated_for_AccountA => OK
      When transfering_2_m_from_AccountA_to_AccountB => OK
      Then it_should_have_1_m_on_AccountA => OK
      Then it_should_have_4_m_on_AccountB => OK
   Transfer_3_m_between_2_accounts => OK
      Given AccountA_has_3_m => OK
      Given AccountB_has_2_m => OK
      Given the_current_user_is_authenticated_for_AccountA => OK
      When transfering_3_m_from_AccountA_to_AccountB => OK
      Then it_should_have_0_m_on_AccountA => OK
      Then it_should_have_5_m_on_AccountB => OK
   Transfer_too_much => OK
      Given AccountA_has_3_m => OK
      Given AccountB_has_2_m => OK
      Given the_current_user_is_authenticated_for_AccountA => OK
      When transfering_4_m_from_AccountA_to_AccountB => OK
      Then it_should_have_3_m_on_AccountA => OK
      Then it_should_have_2_m_on_AccountB => OK
      Then it_should_fail_with_error => OK
   Not_authorized_for_transfer => OK
      Given AccountA_has_3_m => OK
      Given AccountB_has_2_m => OK
      When transfering_1_m_from_AccountB_to_AccountA => OK
      Then it_should_have_3_m_on_AccountA => OK
      Then it_should_have_2_m_on_AccountB => OK
      Then it_should_fail_with_error => OK

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Founder Virtual Sales Lab
Belgium Belgium

Comments and Discussions

 
-- There are no messages in this forum --