diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 669e229b..00000000 --- a/.gitattributes +++ /dev/null @@ -1,22 +0,0 @@ -# Set default behaviour, in case users don't have core.autocrlf set. -* text=crlf - -# Explicitly declare text files we want to always be normalized and converted -# to native line endings on checkout. -*.cs text -*.txt text -*.md text -*.nuspec text -*.config text -*.snk text -*.js text -*.resx text -*.css text -*.sln text -*.csproj text - -# Denote all files that are truly binary and should not be modified. -*.exe binary -*.dll binary - -*.approved.* binary \ No newline at end of file diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index 31d907a9..00000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1 +0,0 @@ -* @SonOfSardaar @MehdiK \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index a0d641e9..00000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,286 +0,0 @@ -name: Build and Test -on: - push: - pull_request: - workflow_dispatch: - inputs: - runPublish: - description: 'Publish Nuget ?' - required: true - default: false - type: boolean - - publishWhichNuget: - description: 'Which Nuget ?' - required: true - default: 'Only Changed' - type: choice - options: - - Only Changed - - All - -jobs: - build: - runs-on: ubuntu-latest - outputs: - semver: ${{ steps.gitversion.outputs.semVer }} - fullsemver: ${{ steps.gitversion.outputs.fullSemVer }} - nugetversion: ${{ steps.gitversion.outputs.fullSemVer }} - publishNuget: ${{ steps.changes.outputs.BddfyUpdated == 'true' || steps.changes.outputs.SamplesUpdated == 'true' || github.event.inputs.publishWhichNuget == 'All' }} - steps: - - name: Checkout code - uses: actions/checkout@v5 - with: - fetch-depth: 0 # Required for GitVersion - - - name: Install GitVersion - uses: gittools/actions/gitversion/setup@v4.1.0 - with: - versionSpec: '6.x' - - - name: Determine Version - uses: gittools/actions/gitversion/execute@v4.1.0 - id: gitversion - - - name: Format NuGet version - run: | - buildNumber="${{steps.gitversion.outputs.preReleaseNumber}}${{ steps.gitversion.outputs.buildMetaData }}" - - if [[ "${GITHUB_REF}" != "refs/heads/${{ github.event.repository.default_branch }}" ]]; then - buildNumber="${buildNumber}-beta" - fi - - packageVersion="${{ steps.gitversion.outputs.majorMinorPatch }}.${buildNumber}" - echo "packageVersion=$packageVersion" >> $GITHUB_OUTPUT - id: formatversion - - - name: Display GitVersion outputs - run: | - echo "Version: ${{ steps.gitversion.outputs.semVer }}" - echo "AssemblyVersion: ${{ steps.gitversion.outputs.assemblySemVer }}" - echo "FileVersion: ${{ steps.gitversion.outputs.assemblySemFileVer }}" - echo "NuGet Version: ${{ steps.gitversion.outputs.fullSemVer }}" - echo "Package Version: ${{ steps.formatversion.outputs.packageVersion }}" - - - name: Setup .NET - uses: actions/setup-dotnet@v5 - with: - dotnet-version: '8.0.x' - - - name: Build project - working-directory: src - run: >- - dotnet build --configuration Release - /p:Version=${{ steps.gitversion.outputs.assemblySemVer }} - /p:AssemblyVersion=${{ steps.gitversion.outputs.assemblySemVer }} - /p:FileVersion=${{ steps.gitversion.outputs.assemblySemFileVer }} - /p:PackageVersion=${{ steps.formatversion.outputs.packageVersion }} - - - name: Run tests with coverage - working-directory: src - env: - DiffEngine_Disabled: 'true' - run: >- - dotnet test - --configuration Release - --collect:"XPlat Code Coverage" - --results-directory ../coverage - - - name: Generate coverage report - uses: danielpalme/ReportGenerator-GitHub-Action@5.4.16 - with: - reports: 'coverage/**/coverage.cobertura.xml' - targetdir: 'coverage-report' - reporttypes: 'Html;Cobertura;TextSummary' - - - name: Display Code Coverage Summary - run: | - echo "## šŸ“Š Code Coverage Summary" >> $GITHUB_STEP_SUMMARY - if [ -f "coverage-report/Summary.txt" ]; then - echo '```' >> $GITHUB_STEP_SUMMARY - cat coverage-report/Summary.txt >> $GITHUB_STEP_SUMMARY - echo '```' >> $GITHUB_STEP_SUMMARY - echo "### Build Log Coverage Summary:" - cat coverage-report/Summary.txt - else - echo "āš ļø Coverage summary file not found" - echo "āš ļø Coverage summary file not found" >> $GITHUB_STEP_SUMMARY - fi - - - name: Generate Rich Release Notes - id: release_notes - uses: mikepenz/release-changelog-builder-action@v5.4.1 - with: - configuration: | - { - "template": "## šŸš€ Release ${{ steps.gitversion.outputs.semVer }}\n\n### šŸ“… Release Information\n- **Version**: ${{ steps.gitversion.outputs.semVer }}\n- **NuGet Version**: ${{ steps.gitversion.outputs.fullSemVer }}\n- **Build Date**: $(date -u +'%Y-%m-%d %H:%M:%S UTC')\n- **Commit**: ${{ github.sha }}\n\n#{{CHANGELOG}}\n\n### šŸ“Š Statistics\n- **Total Changes**: #{{UNCATEGORIZED_COUNT}} commits\n- **Contributors**: #{{CONTRIBUTORS}}\n\n---\n*Generated automatically by GitHub Actions*", - "categories": [ - { - "title": "## šŸš€ Features", - "labels": ["feature", "enhancement", "feat"] - }, - { - "title": "## šŸ› Bug Fixes", - "labels": ["bug", "fix", "bugfix"] - }, - { - "title": "## šŸ“š Documentation", - "labels": ["documentation", "docs"] - }, - { - "title": "## šŸ”§ Maintenance", - "labels": ["maintenance", "chore", "refactor"] - }, - { - "title": "## āš ļø Breaking Changes", - "labels": ["breaking", "breaking-change"] - } - ], - "pr_template": "- #{{TITLE}} (#{{NUMBER}}) by @#{{AUTHOR}}", - "empty_template": "- #{{TITLE}} (#{{HASH}}) by @#{{AUTHOR}}", - "max_pull_requests": 200, - "max_back_track_time_days": 365 - } - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Save Release Notes to File - run: echo "${{ steps.release_notes.outputs.changelog }}" > release-notes.md - - - name: Upload Release Notes as artifact - uses: actions/upload-artifact@v4 - with: - name: release-notes - path: release-notes.md - - - name: Check for changes in project paths - id: changes - run: | - latestTag=$(git describe --tags --abbrev=0) - - if git diff --quiet "$latestTag" HEAD -- src/Samples/; then - echo "SamplesUpdated=false" >> $GITHUB_OUTPUT - else - echo "SamplesUpdated=true" >> $GITHUB_OUTPUT - fi - - if git diff --quiet "$latestTag" HEAD -- src/TestStack.BDDfy/; then - echo "BddfyUpdated=false" >> $GITHUB_OUTPUT - else - echo "BddfyUpdated=true" >> $GITHUB_OUTPUT - fi - - - name: Print changed paths - run: | - echo "SamplesUpdated: ${{ steps.changes.outputs.SamplesUpdated }}" - echo "BddfyUpdated: ${{ steps.changes.outputs.BddfyUpdated }}" - - - name: Create Samples package - working-directory: src - if: steps.changes.outputs.SamplesUpdated == 'true' || github.event.inputs.publishWhichNuget == 'All' - run: >- - dotnet pack ./Samples/TestStack.BDDfy.Samples/*.csproj - --configuration Release - --no-build - /p:PackageVersion=${{ steps.formatversion.outputs.packageVersion }} - --output ../packages - - - name: Create Bddfy package - working-directory: src - if: steps.changes.outputs.BddfyUpdated == 'true' || github.event.inputs.publishWhichNuget == 'All' - run: >- - dotnet pack ./TestStack.BDDfy/*.csproj - --configuration Release - --no-build - /p:PackageVersion=${{ steps.formatversion.outputs.packageVersion }} - --output ../packages - - - name: Upload NuGet package as artifact - uses: actions/upload-artifact@v4 - with: - name: nuget-package - path: packages/*.nupkg - - - name: Publish coverage report as artifact - uses: actions/upload-artifact@v4 - with: - name: coverage-report - path: coverage-report/ - - publish-nuget: - runs-on: ubuntu-latest - needs: build - if: needs.build.outputs.publishNuget == 'true' && (github.event.inputs.runPublish == 'true' || github.ref_name == github.event.repository.default_branch) - environment: - name: Publish - url: https://www.nuget.org/packages/TestStack.BDDfy/ - - steps: - - name: Download NuGet package - uses: actions/download-artifact@v5 - with: - name: nuget-package - path: packages - - - name: Setup .NET - uses: actions/setup-dotnet@v5 - with: - dotnet-version: '8.0.x' - - - name: Publish to NuGet - run: dotnet nuget push packages/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate - - create-release-tag: - runs-on: ubuntu-latest - needs: [build, publish-nuget] - if: github.event.inputs.runPublish == 'true' && github.ref_name == github.event.repository.default_branch - permissions: - contents: write - - steps: - - name: Checkout code - uses: actions/checkout@v5 - with: - fetch-depth: 0 - token: ${{ secrets.GITHUB_TOKEN }} - - - name: Check if tag already exists - id: check_tag - run: | - TAG="v${{ needs.build.outputs.semver }}" - if git rev-parse "$TAG" >/dev/null 2>&1; then - echo "Tag $TAG already exists" - echo "tag_exists=true" >> $GITHUB_OUTPUT - else - echo "Creating new tag: $TAG" - echo "tag_exists=false" >> $GITHUB_OUTPUT - echo "new_tag=$TAG" >> $GITHUB_OUTPUT - fi - - - name: Download Release Notes - if: steps.check_tag.outputs.tag_exists == 'false' - uses: actions/download-artifact@v5 - with: - name: release-notes - path: . - - - name: Create Git Tag and GitHub Release - if: steps.check_tag.outputs.tag_exists == 'false' - run: | - TAG="${{ steps.check_tag.outputs.new_tag }}" - - # Configure git - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - - # Create and push tag - git tag -a "$TAG" -m "Release $TAG" - git push origin "$TAG" - - # Create GitHub release - gh release create "$TAG" \ - --title "Release $TAG" \ - --notes-file release-notes.md \ - --generate-notes - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore deleted file mode 100644 index ad4aa3cb..00000000 --- a/.gitignore +++ /dev/null @@ -1,32 +0,0 @@ -_ReSharper.* -bin/ -obj/ -*.user -*.suo -*~ -*.swp -*.orig -*.nupkg -*.received.txt -*.crunchproject.local.xml -*.crunchsolution.local.xml -*.cache -*.userprefs -.DS_Store -packages/* -PackageBuild/* -Build/* -TestResult.xml -TestStack.BDDfy.sln.ide/graph -_NCrunch_TestStack.BDDfy/ -TestStack.BDDfy.sln.ide/ -src/packages/ -src/.vs/ -.vs/ -project.lock.json -tools/Cake/ -tools/GitReleaseNotes/ -tools/gitversion.commandline/ -artifacts/ -*.code-workspace -**/coverage diff --git a/GitVersion.yml b/GitVersion.yml deleted file mode 100644 index 29e4741b..00000000 --- a/GitVersion.yml +++ /dev/null @@ -1,9 +0,0 @@ -mode: ContinuousDelivery -next-version: 8.0.0 -branches: - main: - increment: Patch - regex: ^main$ - is-release-branch: true -ignore: - sha: [] diff --git a/docs/Customizing/ArchitectureOverview.md b/docs/Customizing/ArchitectureOverview.md deleted file mode 100644 index 17817557..00000000 --- a/docs/Customizing/ArchitectureOverview.md +++ /dev/null @@ -1,100 +0,0 @@ -# Architecture Overview -## Introduction ## -This post provides an overview of the main components of the BDDfy architecture to provide some context for the rest of this section and to illustrate the extensibility points. - -![BDDfy functional decomposition](/img/BDDfy/Customizing/bddfy-functional-decomposition.png) - -The unit of operation in BDDfy is the Story. A Story has metadata (information about the Story) and a collection of Scenarios. Each Scenario represents a test class and contains metadata and a collection of Execution Steps, which are the methods on the test class. There are three types of architectural components in BDDfy: Scanners, Processors and Batch Processors. For each test class BDDfy composes a Story unit with various Scanners and passes it to the Processors in a processor pipeline. Once all of the test classes have been scanned and processed the Batch Processors run aggregate operations against all of the Stories. - -Scanners turn a call to BDDfy (from a method) into a Scenario which could potentially be related to a Story. BDDfy doesn't need Stories but if there is one it uses it. If a Scenario is not related to a Story then it is associated with a dummy placeholder. Each Story is then passed to the Processors, which perform various operations, including executing the tests, and populate the Stories, Scenarios and Steps with the test execution results. Once all of the tests have been scanned and processed, the Batch Processors take the collection of Stories and process their results. This could be any sort of aggregate operation, but currently all the batch processors are reports. - -## Scanners ## -Most of the BDDfy in Action series so far has covered the various Scanners, so I won’t go into much detail here. Suffice to say, BDDfy uses Scanners to scan each test class to find all of the methods on it and turn the test class into a Scenario. The different Scanners are shown here: - -![BDDfy scanners](/img/BDDfy/Customizing/bddfy-scanners.png) - -### Story Scanner ### -BDDfy creates a Story Scanner for each test object. This is the Scanner that actually scans the test object and turns it into a Story. It composes together the Story Metadata Scanner and the appropriate Scenario Scanner – [Fluent](/BDDfy/Usage/FluentAPI.html) or [Reflective](/BDDfy/Usage/MethodNameConventions.html). - -The Story Metadata Scanner gets information from the Story attribute, if one exists on the class. - -A **Story** has the following properties: - -- **Story Metadata**: Information about the Story such as Title, As a, I want, So that -- **Scenarios**: The collection of Scenarios related to the Story -- **Result**: A Story’s Result is a Step Execution Result and is determined by the highest Step Execution Result of its Scenarios. -- **Category**: The Story Category - -**Step Execution Results** have a numerical hierarchy and can be (in ascending order): - -- Not Executed (0) -- Passed (1) -- Not Implemented (2) -- Inconclusive (3) -- Failed (4) - -The Test Runner Processor assigns a numerical Step Execution Result to every Execution Step. The result of a Scenario is then determined by the highest value of from its Steps and the result of a Story is determined by the highest result of its Scenarios. For example, if a Step fails, then its parent Scenario and Story will also have a result of Failed. - -### Scenario Scanners ### -Scenario Scanners scan the test class and use the information they find to create a Scenario. There is a Fluent Scenario Scanner and a Reflective Scenario Scanner. - -A **Scenario** has the following properties: - -- **Title**: The Scenario Title -- **Steps**: The collection of Steps (test class methods) related to the Scenario -- **Result**: A Scenario’s Result is a Step Execution Result and is determined by the highest Step Execution Result of its Steps. -- **Duration**: How long the Scenario took to execute. Used by Diagnostics. - -### Step Scanners ### -Step Scanners turn methods into Execution Steps. The Reflective Scanners (the Executable Attribute Step Scanner and the Method Name Scanner) scan the test class to find all the methods on it and turns them into Execution Steps. The Fluent Step Scanner is only a registry and in practice doesn't do any scanning. - -An **Execution Step** has the following properties: - -- **Title**: The Step Title -- **Result**: The result of executing the Step. -- **Duration**: How long the Step took to execute. Used by Diagnostics. -- **Asserts**: Whether or not the Step is an Assertion Step. -- **Should Report**: Whether the Step should be displayed in reports. -- **Execution Order**: The order that the step should run in relative to the other steps. Can be (in ascending order) - - Initialize (for example, "Context", "Setup) - - Setup State ("Given") - - Consecutive Setup State ("And Given") - - Transition ("When) - - Consecutive Transition "And When") - - Assertion ("Then") - - Consecutive Assertion ("And Then") - - Tear Down ("TearDown") -ā€ƒ -## Processors ## -Once a test class has been scanned into a Story, the Story is passed into a **Processor pipeline** where a series of processing steps are performed on it. The Processors are categorized by Type and the order they run in is determined by this Type. - -The various **Process Types**, in order, are: - -1. Firstly -1. Execute -1. Before Report -1. Report -1. After Report -1. Process Exceptions -1. Finally - -![BDDfy processor pipeline](/img/BDDfy/Customizing/bddfy-processor-pipeline.png) - - -1. **Test Runner (Execute)**: Executes the tests. -1. **Console Reporter (Report)**: Displays the test result in the console. -1. **Exception Processor (Process Exceptions)**: Handles exceptions. -1. **Story Cache (Finally)**: Saves each Story for later processing by the Batch Processors. -1. **Disposer (Finally)**: Cleans up the Story and its Scenarios. - -## Batch Processors ## -Once all of the tests have been scanned and processed, the Batch Processors take all of the Stories and process their results (technically speaking they run in the [AppDomain DomainUnload event](http://msdn.microsoft.com/en-GB/library/system.appdomain.domainunload.aspx)). This could be any sort of result processing, but currently all the batch processors are reports. The built-in Batch Processors are displayed in the diagram below. - -![BDDfy batch processor pipeline](/img/BDDfy/Customizing/bddfy-batch-processor-pipeline.png) - -- **HTML Reporter**: Creates the HTML report -- **Markdown Reporter**: Creates the Markdown report -- **Diagnostics Reporter**: Creates the Diagnostics report - -## Configurator ## -The static Configurator class allows you to configure Scanners, Processors and Batch Processors. It lets you enable, disable, or replace individual components and it also allows you to add custom implementations. diff --git a/docs/Customizing/CustomizingReports.md b/docs/Customizing/CustomizingReports.md deleted file mode 100644 index 559d177a..00000000 --- a/docs/Customizing/CustomizingReports.md +++ /dev/null @@ -1,175 +0,0 @@ -# Customizing Reports -This post looks at how to customize the HTML Report and how to create your own custom reports. You can customize the HTML report via configuration or by applying custom CSS or JavaScript. You can create custom reports either by implementing a new Processor or Batch Processor and adding them into their respective pipelines (see the [Architecture Overview](/BDDfy/Customizing/ArchitectureOverview.html) for details about the differences between these). - -## Customizing the HTML Report ## -The HTML report is the most sophisticated report in [BDDfy](http://teststack.github.io/pages/BDDfy.html) and therefore provides a lot more things that you can configure. Its configuration is defined by the IHtmlReportConfiguration interface. - - public interface IHtmlReportConfiguration - { - string ReportHeader { get; } - string ReportDescription { get; } - string OutputPath { get; } - string OutputFileName { get; } - bool RunsOn(Story story); - } - -You can create a new configuration by implementing that interface or you can inherit from the DefaultHtmlReportConfiguration class, used to configure the standard HTML Report, and just override specific properties. Here is an example of a custom configuration, taken from the ATM sample, available on github [here](https://github.com/TestStack/TestStack.BDDfy/tree/master/TestStack.BDDfy.Samples/Atm). - - public class HtmlReportConfig : DefaultHtmlReportConfiguration - { - public override bool RunsOn(Core.Story story) - { - return story.MetaData.Type.Namespace != null && story.MetaData.Type.Namespace.EndsWith("Atm"); - } - - /// - /// Change the output file name - /// - public override string OutputFileName - { - get - { - return "ATM.html"; - } - } - - /// - /// Change the report header to your project - /// - public override string ReportHeader - { - get - { - return "ATM Solutions"; - } - } - - /// - /// Change the report description - /// - public override string ReportDescription - { - get - { - return "A reliable solution for your offline banking needs"; - } - } - } - -which produces the following customised report, which you will find in your bin directory named ATM.html: - -![BDDfy functional decomposition](/img/BDDfy/Customizing/bddfy-sample-atm-html-custom.png) - - -The HTML report is a [Batch Processor](/BDDfy/Customizing/ArchitectureOverview.html) and is implemented by the HtmlReporter class. To plug the new report into BDDfy you need to create a new HtmlReporter and pass the custom configuration into its constructor. As I explained in the [Reports post](/BDDfy/Usage/Reports.html), the place to apply that configuration to BDDfy is the Configurator class, which is called before the tests run. - - Configurator.BatchProcessors.Add(new HtmlReporter(new HtmlReportConfig())); - -The use of the Add method means this is adding a second HTML Report processor into the Batch Processor pipeline, so the default report runner will still run. If you actually want the new report to replace the default report, then you will also need to disable the default report. - - Configurator.BatchProcessors.HtmlReport.Disable(); - -## Custom CSS and JavaScript ## -You can customize a lot more about the HTML report. BDDfy uses the BDDfy.css file to style the report and BDDfy.js and jQuery to add interactivity to it. You will find these files in the bin directory alongside the HTML report. You can customise the styles by adding a bddifyCustom.css class and the behaviour by adding a bddifyCustom.js file. These files also need to be in the same directory as the HTML report file. This will affect all the reports in the project. - - -## Create a custom report by creating a new Processor ## -One way to create a custom report is to implement a new Processor and plug it into the Processor pipeline. You just have to implement the one Process() method and set the Process Type to Report. - -An example of doing this is provided in the BDDfy Tic Tac Toe sample project with the Custom Text Reporter. The sample is available on [github](https://github.com/TestStack/TestStack.BDDfy/tree/master/TestStack.BDDfy.Samples) or [nuget](http://nuget.org/packages/TestStack.BDDfy.Samples/). - - /// - /// This is a custom reporter that shows you how easily you can create a custom report. - /// Just implement IProcessor and you are done - /// - public class CustomTextReporter : IProcessor - { - private static readonly string Path; - - private static string OutputDirectory - { - get - { - string codeBase = typeof(CustomTextReporter).Assembly.CodeBase; - var uri = new UriBuilder(codeBase); - string path = Uri.UnescapeDataString(uri.Path); - return System.IO.Path.GetDirectoryName(path); - } - } - - static CustomTextReporter() - { - Path = System.IO.Path.Combine(OutputDirectory, "BDDfy-text-report.txt"); - - if(File.Exists(Path)) - File.Delete(Path); - - var header = - " A custom report created from your test assembly with no required configuration " + - Environment.NewLine + - Environment.NewLine + - Environment.NewLine + - Environment.NewLine; - File.AppendAllText(Path, header); - } - - public void Process(Story story) - { - // use this report only for tic tac toe stories - if (!story.MetaData.Type.Name.Contains("TicTacToe")) - return; - - var scenario = story.Scenarios.First(); - var scenarioReport = new StringBuilder(); - scenarioReport.AppendLine(string.Format(" SCENARIO: {0} ", scenario.Title)); - - if (scenario.Result != StepExecutionResult.Passed && scenario.Steps.Any(s => s.Exception != null)) - { - scenarioReport.Append(string.Format(" {0} : ", scenario.Result)); - scenarioReport.AppendLine(scenario.Steps.First(s => s.Result == scenario.Result).Exception.Message); - } - - scenarioReport.AppendLine(); - - foreach (var step in scenario.Steps) - scenarioReport.AppendLine(string.Format(" [{1}] {0}", step.StepTitle, step.Result)); - - scenarioReport.AppendLine("--------------------------------------------------------------------------------"); - scenarioReport.AppendLine(); - - File.AppendAllText(Path, scenarioReport.ToString()); - } - - public ProcessType ProcessType - { - get { return ProcessType.Report; } - } - } - -This produces the BDDfy-text-report.txt text file report which is output to the bin directory: - -![BDDfy custom text report](/img/BDDfy/Customizing/bddfy-custom-text-report.png) - -## Create a custom report by creating a new Batch Processor ## -While that is one way that you can create a custom report, probably the better way to do it is to implement a new Batch Processor. The Processor runs as each test is being executed and allows you to build up the report, whereas a Batch Processor has the advantage of running after all of the tests have finished, meaning that you have access to total and summary information, such as diagnostics. - -As an example of creating a custom report by creating a new Batch Processor, I was recently messing around with running tests in parallel and, as you might expect, the normal console report was quite jumbled. Multiple console report Processors were writing to the console at the same time and different test results were overlapping. The solution was to run the console report after all of the tests had run by creating a new Console Reporter as a Batch Processor rather than a Processor. - - public class MyConsoleReporter : IBatchProcessor - { - public void Process(IEnumerable stories) - { - var reporter = new ConsoleReporter(); - stories - .ToList() - .ForEach(story => reporter.Process(story)); - } - } - -Then I just needed to add it to the Batch Processor pipeline and disable the built-in console report: - - Configurator.Processors.ConsoleReport.Disable(); - Configurator.BatchProcessors.Add(new MyConsoleReporter()); - - -That's a bit of a hack for demo purposes. The HTML, MarkDown, and Diagnostics reports are all implemented as Batch Processors and I would recommend checking them out for examples of how to create a new report. diff --git a/docs/Customizing/ExampleCustomFramework.md b/docs/Customizing/ExampleCustomFramework.md deleted file mode 100644 index 86018822..00000000 --- a/docs/Customizing/ExampleCustomFramework.md +++ /dev/null @@ -1,390 +0,0 @@ -# Example - Creating a custom framework -## Introduction ## -This post provides some sample code to demonstrate some of the BDDfy extension points, and to provide a reference point for some of your own customizations. In this example we modify BDDfy to work as a context specification framework, similar to [mspec](https://github.com/machine/machine.specifications). - -So, the requirements for this hypothetical custom framework are - -- It should use the context specification grammar (Establish Context, Because Of, It Should) rather than the Given When Then grammar that BDDfy uses by default -- It should have a Class per Scenario style, like the [Testcase class per Fixture](http://xunitpatterns.com/Testcase%20Class%20per%20Fixture.html) pattern from Gerard Meszaros’ [XUnit Test Patterns](http://www.amazon.com/xUnit-Test-Patterns-Refactoring-Code/dp/0131495054/ref=sr_1_1?s=books&ie=UTF8&qid=1368296304&sr=1-1&keywords=xunit+test+patterns) book (a book which I highly recommend). -- It should not require any testing framework, such as NUnit or MsTest. In fact, the only dependency will be BDDfy. -- It should not require a test runner, such as TestDriven.Net or ReSharper -- I’m not a fan of attributes, so no attributes for the BDDfy Story, the test fixture or for the test methods -- The HTML report should be customised for my new framework. (Let’s call it Context Specifier). -- Finally, I would like to be able to run tests sequentially or in parallel - -## ContextSpecification Base Class ## - -I am going to start off with a base class to establish the context specification method template. I’ll also put a Story property here as an alternative to the Story attribute so that each specification can specify the Story that they belong to. BDDfy does not require Scenarios to have a Story, but it’s a convention I’m wanting to enforce for this framework! The Run method is what calls BDDfy to run the test. By default it will call BDDfy() and BDDfy will convert the class name into the scenario title. If I want to override that value I just need to set the ScenarioTitle in the class constructor and then it will be used with the BDDfy(scenarioTitle) overload. - -This is actually the only time that BDDfy is called in this framework and the whole test suite. It is very DRY and I much prefer it to adding fixture and test attributes for every test. (By the way, even if I were using a framework like nunit/xunit this base class would still be the only place I would need to use their attributes or call BDDfy. Their runners are smart enough to find the test classes, which is a nice benefit of using inheritance in this sort of framework). - - public abstract class ContextSpecification - { - protected virtual void EstablishContext() { } - protected virtual void BecauseOf() { } - - public abstract UserStory Story { get; } - - public virtual string ScenarioTitle { get; set; } - - public void Run() - { - if (string.IsNullOrEmpty(ScenarioTitle)) - { - this.BDDfy(); - } - else - { - this.BDDfy(ScenarioTitle); - } - } - } - -With this base class in place I can write a class for each scenario. To do that, I’m going to modify the BDDfy ATM samples. The Context Specification style utilises the same four-phase test pattern as Arrange Act Assert or Given When Then, setting up the pre-conditions for the test in the Establish Context phase, exercising the system under test (SUT) in the Because Of phase, and then verifying expectations in the It Should phase. - -The user story is associated with the specification by setting the Story property to a new instance of a UserStory class - in this case the AtmWithdrawCashStory class. Notice that I am able to override the scenario title in the constructor, so the report will read "When account funds are less than zero" rather than "When account has insufficient funds" which BDDfy would derive from the class name. - - public class WhenAccountHasInsufficientFunds : ContextSpecification - { - private Card _card; - private Atm _atm; - - public WhenAccountHasInsufficientFunds() - { - ScenarioTitle = "When account funds are less than zero"; - } - - protected override void EstablishContext() - { - _card = new Card(true, 10); - _atm = new Atm(100); - } - - protected override void BecauseOf() - { - _atm.RequestMoney(_card, 20); - } - - public override UserStory Story - { - get { return new AtmWithdrawCashStory(); } - } - - void ItShouldNotDispenseAnyMoney() - { - Assert.AreEqual(0, _atm.DispenseValue); - } - - void AndItShouldSayThereAreInsufficientFunds() - { - Assert.AreEqual(DisplayMessage.InsufficientFunds, _atm.Message); - } - - void AndItShouldHaveTheSameAccountBalance() - { - Assert.AreEqual(10, _card.AccountBalance); - } - - void AndItShouldReturnTheCard() - { - Assert.IsFalse(_atm.CardIsRetained); - } - } - -## The Context Specification Grammar ## - -To use my new grammar instead of the default BDDfy Given When Then grammar I need to tell BDDfy how to find step methods on the class, which I can do by replacing the BDDfy DefaultMethodNameStepScanner with a new MethodNameStepScanner. BDDfy defines the Given When Then grammar in the DefaultMethodNameStepScanner and the easiest way to create a new scanner is to copy and modify that. - - public class ContextSpecificationStepScanner : MethodNameStepScanner - { - public ContextSpecificationStepScanner() - : base( - CleanupTheStepText, - new[] - { - new MethodNameMatcher(s => s.StartsWith("EstablishContext", StringComparison.OrdinalIgnoreCase), false, ExecutionOrder.SetupState, false), - new MethodNameMatcher(s => s.StartsWith("BecauseOf", StringComparison.OrdinalIgnoreCase), false, ExecutionOrder.Transition, false), - new MethodNameMatcher(s => s.StartsWith("It", StringComparison.OrdinalIgnoreCase), true, ExecutionOrder.Assertion, true), - new MethodNameMatcher(s => s.StartsWith("AndIt", StringComparison.OrdinalIgnoreCase), true, ExecutionOrder.ConsecutiveAssertion, true) - }) - { - } - - static string CleanupTheStepText(string stepText) - { - if (stepText.StartsWith("EstablishContext", StringComparison.OrdinalIgnoreCase)) - return "Establish context "; - - if (stepText.StartsWith("BecauseOf", StringComparison.OrdinalIgnoreCase)) - return "Because of "; - - if (stepText.StartsWith("AndIt ", StringComparison.OrdinalIgnoreCase)) - return stepText.Remove("and".Length, "It".Length); - - return stepText; - } - } - -The custom scanner requires two parameters in the constructor; a step text transformer and an array of MethodNameMatchers. Each MethodNameMatcher defines a predicate to identify if the method matches, whether or not the method is an assertion, the type of method it is, and whether it should be displayed on the report. With Given When Then steps you want to display all of the steps on the report. With my context specification grammar I just want to display the name of the class and the assertions, so I specify false for the shouldReport parameter of the ā€œEstablishContextā€ and ā€œBecauseOfā€ steps so that they won’t display on the report. This is not something we recommend, as it would be helpful to receive error messages for those steps if they fail, but it makes sense for reporting purposes with this grammar as repeating EstablishContext and BecauseOf would not be much use on the report (and a reason why Given When Then grammar is preferable to this one). - -Once I have my new grammar I need to tell BDDfy to use it by using the Configurator to disable the default scanner and to add the new one: - - Configurator.Scanners.DefaultMethodNameStepScanner.Disable(); - Configurator.Scanners.Add(() => new ContextSpecificationStepScanner()); - -## Replacing the BDDfy Story Attribute ## - -The next thing on my list is the Story. BDDfy uses an attribute on the test class to specify the Story that the Scenario test class belongs to. You are not limited to this though, and like most things in BDDfy, you are able to customise this behaviour if you want. I’m going to create a simple UserStory class that stores Story metadata. It is just a standard class that does not implement any BDDfy behaviours. I could potentially just use the BDDfy StoryMetaData class directly, but I will keep things separate for now. - - public abstract class UserStory - { - public string Title { get; set; } - public string AsA { get; set; } - public string IWant { get; set; } - public string SoThat { get; set; } - } - - -To create a new story class, I just have to inherit from the UserStory class and set the metadata properties in its constructor. Here is the AtmWithdrawCashStory from the example above. - - public class AtmWithdrawCashStory : UserStory - { - public AtmWithdrawCashStory() - { - Title = "Withdrawing cash from the ATM"; - AsA = "As an Account Holder"; - IWant = "I want to withdraw cash from an ATM"; - SoThat = "So that I can get money when the bank is closed"; - } - } - -To tell BDDfy how to find these Stories and match them to the appropriate Scenario, I need to implement a new Story Metadata Scanner to associate the Scenario test class with its Story. - - public class StoryMetaDataScanner : IStoryMetaDataScanner - { - public StoryMetaData Scan(object testObject, Type explicitStoryType = null) - { - var specification = testObject as ContextSpecification; - if (specification == null) - return null; - - var story = specification.Story; - - return new StoryMetaData(story.GetType(), story.AsA, story.IWant, story.SoThat, story.Title); - } - } - -My convention of having all my test classes inherit from the base ContextSpecifcation comes in handy here as it enables me to easily get access to the Story property and use it to create the StoryMetaData that BDDfy needs. Now, I can just replace the BDDfy StoryMetaDataScanner with my custom one using the Configurator. - - Configurator.Scanners.StoryMetaDataScanner = () => new StoryMetaDataScanner(); - -## Customizing the HTML Report ## - -I want to change the HTML report to have the name and description of the framework and to change the name of the html file that is generated. You can do this by inheriting from the DefaultHtmlReportConfiguration class. - - public class CustomHtmlReportConfiguration : DefaultHtmlReportConfiguration - { - public override string ReportHeader - { - get - { - return "Context Specifier"; - } - } - - public override string ReportDescription - { - get - { - return "A simple context specification framework for .Net developers"; - } - } - - public override string OutputFileName - { - get - { - return "ContextSpecifications.html"; - } - } - } - -I can then turn off the default HTML Report and plug the custom one in instead: - - Configurator.BatchProcessors.HtmlReport.Disable(); - Configurator.BatchProcessors.Add(new HtmlReporter(new CustomHtmlReportConfiguration())); - -## Test Runner ## -The Test Runner is quite straightforward. We just have to instantiate all of the specification classes and call the Run method. You could new up each class, use reflection to find all the classes that derive from ContextSpecification (as I’ve done here) or use an IoC container to store and retrieve them. - - public class TestRunner - { - public void Run() - { - RunTestsSequentially(); - RunBatchProcessors(); - } - - private void RunTestsSequentially() - { - //new WhenAccountHasInsufficientFunds().Run(); - //new WhenCardHasBeenDisabled().BDDfy(); - //new WhenAccountHasSufficientFunds().BDDfy(); - - GetSpecs().Each(spec => SafeRunSpec(spec)); - } - - private void SafeRunSpec(ContextSpecification spec) - { - try - { - spec.Run(); - } - catch (Exception) - { - } - } - - private void RunBatchProcessors() - { - foreach (var batchProcessor in Configurator.BatchProcessors.GetProcessors()) - { - batchProcessor.Process(StoryCache.Stories); - } - } - - private List GetSpecs() - { - return this.GetType() - .Assembly - .GetTypes() - .Where(type => type.IsSubclassOf(typeof(ContextSpecification))) - .Select(Activator.CreateInstance) - .Cast() - .ToList(); - } - } - - -If you were to just run the tests like this then you would see the Console Report display all the tests in the console window. However, none of the Batch Processors, such as the HTML Report, would run. BDDfy runs these in the AppDomain_Unload event and one down side of my running in a console app is that [this event is not raised in the default application domain](http://msdn.microsoft.com/en-us/library/system.appdomain.domainunload%28VS.90%29.aspx). No worries, BDDfy makes it easy to run ourselves so I’ve added the RunBatchProcessors method. If you check the bin directory of the console application you will see our customised HTML Report with the context specification grammar. - -## Wiring It All Up ## -All that is left is to wire up a console application to run the tests. The first step is to configure BDDfy, which I’ve already shown. To run the tests I just need to instantiate the TestRunner and call the Run method. - - class Program - { - static void Main(string[] args) - { - ConfigureBDDfy(); - new TestRunner().Run(); - - Console.ReadLine(); - } - - private static void ConfigureBDDfy() - { - Configurator.Scanners.DefaultMethodNameStepScanner.Disable(); - Configurator.Scanners.Add(() => new ContextSpecificationStepScanner()); - - Configurator.Scanners.StoryMetaDataScanner = () => new StoryMetaDataScanner(); - - Configurator.BatchProcessors.HtmlReport.Disable(); - Configurator.BatchProcessors.Add(new HtmlReporter(new CustomHtmlReportConfiguration())); - } - } - -If you go to the bin directory of the test project you should see the report file with the custom name, "ContextSpecifications.html," and all of the custom content inside it. - -![BDDfy custom framework](/img/BDDfy/Customizing/bddfy-custom-framework-report.png) - - -# Running the tests in parallel # -In the never ending quest for faster running tests, being able to run them in parallel can be a great way to speed things up. The first problem I have to solve is to batch up the list of tests into smaller lists of a fixed size that can be run in parallel. I found an excellent extension method for that by David Boike [here](http://www.make-awesome.com/2010/08/batch-or-partition-a-collection-with-linq/): - - public static class Extensions - { - public static IEnumerable> Batch(this IEnumerable collection, int batchSize) - { - List nextbatch = new List(batchSize); - foreach (T item in collection) - { - nextbatch.Add(item); - if (nextbatch.Count == batchSize) - { - yield return nextbatch; - nextbatch = new List(batchSize); - } - } - if (nextbatch.Count > 0) - yield return nextbatch; - } - } - -Then I can add a method to the TestRunner that uses the Batch extension method to break the list of tests into batches that can be run using the [Parallel ForEach](http://msdn.microsoft.com/en-us/library/system.threading.tasks.parallel.foreach.aspx) method. This is the parallel version of the standard, sequential foreach loop. - - private void RunTestsInParallel(int batchSize) - { - List theSpecs = GetSpecs(); - var batch = theSpecs.Batch(batchSize); - - Parallel.ForEach(batch, specs => specs.Each(spec => SafeRunSpec(spec))); - } - - -This can be plugged into the Run method by adding an optional batch size parameter, which allows the existing code to work as it is and for tests to run in parallel by passing a batchSize value of more than zero into the Run method. - - public class TestRunner - { - public void Run(int batchSize = 0) - { - if (batchSize == 0) - { - RunTestsSequentially(); - } - else - { - RunTestsInParallel(batchSize); - } - RunBatchProcessors(); - } - ... - } - -## Batch Console Reporter ## -There is one problem with this code though. The parallel nature of the loop means that multiple iterations may be executing at the same time and, as might be expected, the normal console report becomes quite jumbled. - -![BDDfy console report for parallel tests](/img/BDDfy/Customizing/bddfy-console-parallel-broken.png) - -The solution is to run the console report after all of the tests have completed. This can be achieved by creating a new Console Reporter as a Batch Processor rather than a Processor. The Processor runs as each test is being executed and allows you to build up the report, whereas a Batch Processor has the advantage of running after all of the tests have finished (see the [Architecture Overview](/BDDfy/Customizing/ArchitectureOverview.html) post for more detail). - - public class MyConsoleReporter : IBatchProcessor - { - public void Process(IEnumerable stories) - { - var reporter = new ConsoleReporter(); - stories - .ToList() - .ForEach(story => reporter.Process(story)); - } - } - -Then I just needed to add it to the Batch Processor pipeline and disable the built-in console report. For convenience I have just added it to the RunTestsInParallel method: - - private void RunTestsInParallel(int batchSize) - { - Configurator.Processors.ConsoleReport.Disable(); - Configurator.BatchProcessors.Add(new BatchConsoleReporter()); - - List theSpecs = GetSpecs(); - var batch = theSpecs.Batch(batchSize); - - Parallel.ForEach(batch, specs => specs.Each(spec => SafeRunSpec(spec))); - } - - - - -So, there it is. A bit of a contrived example, but hopefully it has highlighted some of the extensibility points that BDDfy offers and provided some food for thought for some customizations that you might like to try yourself. - -The code is available on github: -[https://github.com/mwhelan/BDDfySamples](https://github.com/mwhelan/BDDfySamples) diff --git a/docs/Customizing/ExampleUnitTesting.md b/docs/Customizing/ExampleUnitTesting.md deleted file mode 100644 index b5979c75..00000000 --- a/docs/Customizing/ExampleUnitTesting.md +++ /dev/null @@ -1,224 +0,0 @@ -# Example - Using BDDfy for unit testing -# Introduction # -I’ve been using BDDfy with NUnit for writing acceptance tests for quite awhile now. But for unit testing I have continued to use mspec with [machine fakes](https://github.com/machine/machine.fakes) and Moq for auto-mocking. The more I used BDDfy, the more I liked it, and the less I liked the context switch into another framework. I found myself wanting to write unit tests in the Given When Then format and didn't like having to maintain two sets of helper code for NUnit and mspec. I loved the reporting in BDDfy and started to think it would be pretty cool to have similar reporting for my unit tests. Basically, I wanted a consistent experience across all my automated testing. - -MSpec uses the [testcase class per fixture](http://xunitpatterns.com/Testcase%20Class%20per%20Fixture.html) style of testing, which is how I use BDDfy for acceptance testing, so it makes sense to continue with that style for the BDDfy unit tests. When I am doing acceptance tests I have a base ScenarioFor< T> class, where the T represents the System Under Test (SUT). Because these are full system tests, I resolve this SUT using the same inversion of control container that my application uses, which works nicely. The IoC container acts as a [SUT factory](http://blog.ploeh.dk/2009/02/13/SUTFactory/). With unit tests, I also want to have a SUT factory, but instead I want it to be an auto-mocking container. - -When we started writing unit tests for the [Seleno](http://teststack.github.io/pages/Seleno.html) project, I thought it would be a good opportunity to try some of these ideas out. - -# Specification Base Fixture # -The Specification base fixture class wires up BDDFy. It provides methods that BDDfy knows about in its default configuration for setting up and tearing down the fixture (each test class will implement its own specific Given When Then methods that BDDfy will also find). The Run method has the NUnit Test attribute and so will be called by the testing framework and it just calls BDDFy to run the test. I prefer to use NUnit myself, but you could just as easily substitute XUnit or MsTest attributes if you prefer. One thing I really like about this approach is that I only have to put the TestFixture and Test attributes in this one class and then all of the test classes I create inherit them and don't need any attributes. All the test runners still picks the classes up as tests and ReSharper even puts its little run test icons in each test class as normal. This class is also the one place that BDDfy gets called. - - [TestFixture] - public abstract class Specification : ISpecification - { - [Test] - public virtual void Run() - { - string title = BuildTitle(); - this.BDDfy(title, Category); - } - - protected virtual string BuildTitle() - { - return Title ?? GetType().Name.Humanize(LetterCasing.Title); - } - - // BDDfy methods - public virtual void EstablishContext() { } - public virtual void Setup() { } - public virtual void TearDown() { } - - public virtual Type Story { get { return GetType(); } } - public virtual string Title { get; set; } - public string Category { get; set; } - } - -#Auto-Mocking # -The SpecificationFor class inherits from the Specification class and adds an auto-mocking container for creating the SUT. An auto-mocking container decouples a unit test from the mechanics of creating the SUT and automatically supplies dynamic mocks in place of all of the SUT's dependencies. They are commonly implemented by combining an IoC container with a mocking framework, which is what I will be doing here. I prefer [NSubstitute](http://nsubstitute.github.io/) for mocking these days, so my friend [Rob Moore's](http://robdmoore.id.au/) [AutoSubstitute](http://nuget.org/packages/AutofacContrib.NSubstitute) auto-mocking container is ideal. - -The AutoSubstitute field provides access to the container for full access to its functionality. SubstituteFor is provided as a convenience method to gain access to NSubstitute substitutes. - - public abstract class SpecificationFor : Specification - { - public T SUT { get; set; } - protected AutoSubstitute AutoSubstitute; - - protected SpecificationFor() - { - AutoSubstitute = CreateContainer(); - InitialiseSystemUnderTest(); - } - - public virtual void InitialiseSystemUnderTest() - { - SUT = AutoSubstitute.Resolve(); - } - - public TSubstitute SubstituteFor() where TSubstitute : class - { - return AutoSubstitute.ResolveAndSubstituteFor(); - } - - public override Type Story - { - get { return typeof(T); } - } - - private static AutoSubstitute CreateContainer() - { - Action autofacCustomisation = c => c - .RegisterType() - .FindConstructorsWith(t => t.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) - .PropertiesAutowired(); - return new AutoSubstitute(autofacCustomisation); - } - } - -Notice that the InitialiseSystemUnderTest is virtual, so if you need to create the SUT yourself rather than having AutoSubstitute do it then you can just override it in your test class. It runs before any of the test methods so they can all safely interact with the SUT confident that it has been created. - -# What's in a Story? # -When moving from scenarios to unit tests I had to think what I wanted to do with the Story that is part of BDD. BDDfy actually doesn't require stories, so one option was to do nothing. However, when you don't have a story the report shows the namespace instead, and I don't find that particularly helpful or attractive. A Story's purpose in BDD is to group related Scenarios and to provide metadata about that grouping, so I think the same logic can be applied to unit tests. - -By creating a base specification class that related tests inherit from, they will all be grouped together on the report, and the name of that class will be used in the heading, much like a Story grouping would look like on a BDD report. This class is often a convenient place to create variables that are common to all of the test cases. So, for example, if you create a base class called PageNavigatorSpecification, the report grouping will read "Specifications For: Page Navigator." That is achieved by adding the following custom story metadata scanner. - - public class SpecStoryMetaDataScanner : IStoryMetaDataScanner - { - public virtual StoryMetaData Scan(object testObject, Type explicityStoryType = null) - { - var specification = testObject as ISpecification; - if (specification == null) - return null; - - string specificationTitle = CreateSpecificationTitle(specification); - var story = new StoryAttribute() {Title = specificationTitle}; - return new StoryMetaData(specification.Story, story); - } - - private string CreateSpecificationTitle(ISpecification specification) - { - string suffix = "Specification"; - string title = specification.Story.Name; - if (title.EndsWith(suffix)) - title = title.Remove(title.Length - suffix.Length, suffix.Length); - return title; - } - } - -And here is what the specifications look like in the BDDfy report: - -![BDDfy unit test report](/img/BDDfy/Customizing/bddfy-unit-test-report.png) - -# Unit Testing # -Here is an example of some tests that we have written for Seleno using this approach. Firstly, an example of a Specification class, the grouping class analagous to the BDDFy story that all the PageReader specification classes will inherit from. There is normally no need to override the Story as the SpecificationFor class will automatically convert the generic T into an English name. In this case though it will convert PageReader< TestViewModel> into PageReader`, so it is a convenient hack to override the property with PageReaderSpecification which will more attractively produce "Page Reader" on the report. - - abstract class PageReaderSpecification : SpecificationFor> - { - public override Type Story - { - get { return typeof (PageReaderSpecification); } - } - } - -Each specification for the PageReader component inherits from the PageReaderSpecification. There are often no Given steps as the auto-mocking container has taken care of instantiating the SUT for you. It has also created a Substitute for the IExecutor dependency of the PageReader class and in the verification phase of the test you can just call SubstituteFor< IExecutor> to call NSubstitute verification methods on the substitute. - - class When_checking_an_element_exists_and_is_visible_with_property : PageReaderSpecification - { - public When_checking_an_element_exists_and_is_visible_with_property() - { - SUT.ExistsAndIsVisible(x => x.Item); - } - - public void Then_it_should_execute_the_relevant_script_with_jquery_id_selector() - { - SubstituteFor() - .Received() - .ScriptAndReturn("$(\"#Item\").is(':visible')"); - } - } - -This test shows that you can also setup Substitute behaviour in the setup phase of the test. - - class When_getting_a_web_element_strongly_typed_text : PageReaderSpecification - { - private DateTime _result; - private readonly DateTime _the03rdOfJanuary2012At21h21 = new DateTime(2012, 01, 03, 21, 21, 00); - - [Given("Given a web element contains the text 03/01/2012 21:21")] - public void Given_a_web_element_contains_the_text_03_01_2012_21_21() - { - SubstituteFor() - .Element(Arg.Any()) - .Returns(SubstituteFor()); - - SubstituteFor().Text.Returns("03/01/2012 21:21"); - } - - public void When_getting_the_web_element_matching_a_view_model_property() - { - _result = SUT.TextAsType(viewModel => viewModel.Modified); - } - - public void Then_it_should_return_the_corresponding_typed_value_of_the_web_element_text() - { - _result.Should().Be(_the03rdOfJanuary2012At21h21); - } - } - -# Another approach # -It's worth looking at another example of sharing a base context class. As I said above, it is not just for making the report work, it can be quite helpful to share context there. [Matt Honeycutt](http://trycatchfail.com/blog/) has an interesting style for reusing context classes in his very cool [SpecsFor BDD framework](http://specsfor.com/) that this approach also supports: - - public class given - { - public abstract class the_command_is_valid : SpecificationFor - { - protected void Given_the_command_is_valid() - { - SubFor>().Validate(Arg.Any()).Returns(new ExecutionResult(null)); - SubFor().ValidatorForCommand(Arg.Any()).Returns(SubFor>()); - } - } - } - - public class processing_a__valid_command : given.the_command_is_valid - { - private TestCommand _command = new TestCommand(); - private ExecutionResult _result; - - public void when_processing_a_valid_command() - { - _result = SUT.Execute(_command); - } - - public void Then_the_processor_should_find_the_validator_for_the_command() - { - SubFor().Received().ValidatorForCommand(_command); - } - - public void AndThen_validate_the_command() - { - SubFor>().Received().Validate(_command); - } - - public void AndThen_the_processor_should_find_the_handler_for_the_command() - { - SubFor().Received().HandlerForCommand(_command); - } - - public void AndThen_the_command_is_processed_successfully() - { - _result.IsSuccessful.Should().BeTrue(); - } - - public void AndThen_the_result_is_logged() - { - SubFor().Received().Info(Arg.Any()); - } - } - -And this comes out very nicely on the report: - -![BDDfy unit test report](/img/BDDfy/Customizing/bddfy-unit-test-report-2.png) - - -You can find the code on [github](https://github.com/TestStack/TestStack.Seleno/tree/master/src/TestStack.Seleno.Tests/Specify). diff --git a/docs/Customizing/index.md b/docs/Customizing/index.md deleted file mode 100644 index 837a4599..00000000 --- a/docs/Customizing/index.md +++ /dev/null @@ -1,4 +0,0 @@ -# Customizing BDDfy -BDDfy strives to be very extensible: Its core barely has any logic in it all its responsibilities are delegated to extensions, all of which are configurable. For example, if you don't like the reports it generates, you can write your custom reporter in a few lines of code. - -This section will look at the extensibility points and provide samples of customizing BDDfy. diff --git a/docs/Usage/BDDExamples.md b/docs/Usage/BDDExamples.md deleted file mode 100644 index 026b661e..00000000 --- a/docs/Usage/BDDExamples.md +++ /dev/null @@ -1,35 +0,0 @@ -# Examples - - -## Actions as examples -One of the benefits that BDDfy's approach has it its flexibility. - -``` csharp -ExampleAction actionToPerform = null; -int valueShouldBe = 0; -var story = this.Given(_ => SomeSetup()) - .When(() => actionToPerform) - .Then(_ => ShouldBe(valueShouldBe)) - .WithExamples(new ExampleTable("Action to perform", "Value should be") - { - { new ExampleAction("Do something", () => { _value = 42; }), 42 }, - { new ExampleAction("Do something else", () => { _value = 7; }), 7 } - }) - .BDDfy(); -``` - -When run you will get this: - -``` -Scenario: Can use actions in examples - Given some setup - When - Then should be - -Examples: -| Action to perform | Value should be | -| Do something | 42 | -| Do something else | 7 | -``` - -This can make your BDD test incredibly flexible and powerful. diff --git a/docs/Usage/ExecutableAttributes.md b/docs/Usage/ExecutableAttributes.md deleted file mode 100644 index 542aaeea..00000000 --- a/docs/Usage/ExecutableAttributes.md +++ /dev/null @@ -1,320 +0,0 @@ -# Executable Attributes - -Before I start I should mention that this post is going to look rather similar to the one about [Method Name Conventions](/BDDfy/MethodNameConventions.html) because these two methods are similar in nature. Also the samples provided in this post are by no means perfect BDD samples and are used only to demonstrate the API usage. - -As mentioned in the previous post BDDfy can scan your tests in one of two ways: using Reflective API and Fluent API. Reflective API uses some hints to scan your classes. You can provide these hints in two ways: using method name conventions and/or attributes. We have discussed [method name conventions](/BDDfy/MethodNameConventions.html) before and in this post we will only concentrate on `ExecutableAttribute`. - -In the reflective mode you could use Method Name Conventions to provide BDDfy with some hints about your test steps. That is all good; but in some cases you may need to explicitly specify your test steps and/or their title (or at least some of them): - -##You may need more control over the step title -When using Method Name Conventions BDDfy uses your method name to generate the step title. This works in a lot cases; but in some cases you may need more control over your step title. For example your step title may need to have special characters; e.g. "Given the ATM doesn't have enough cash". For BDDfy to be able to derive this your method should be called "GivenTheAtmDoesn'tHaveEnoughCash" which of course is not a valid method name. Even if that was a valid method name the result would be "Given the atm doesn't have enough cash" where 'atm' is all lower case! - -##What if Method Name Conventions do not make sense? -In vast majority of cases method name conventions make your methods and tests more readable and maintainable; but there may be cases when you want to use different method names because they may read better. As an example you may have a scenario that is written as: - -
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-
-namespace BDDfy.ExecutableAttributes
-{
-    [TestClass]
-    public class NonCompliantMethodNames
-    {
-        [TestMethod]
-        public void ShouldBeAbleToRunScenariosWithNonCompliantMethodNames()
-        {
-            this.BDDfy();
-        }
-
-        void GivenSomeMethodsDoNotComplyWithBDDfyMethodNameConventions()
-        {
-        }
-
-        void WhenExecutableAttributeIsApplied()
-        {
-        }
-
-        void BDDfyCanPickupTheSteps()
-        {
-        }
-
-        void ThatAreDecoratedWithTheAttributes()
-        {
-        }
-    }
-}
-
- -The last two methods, which are my 'Then' and 'And then' steps, do not comply with method name conventions and as such will not be picked up by BDDfy! - -##So what are ExecutableAttributes? -In cases when method name conventions do not cut it for you, you may use `ExecutableAttribute` to nominate any method as a step. So let's just change the above example so it works: - -
-using BDDfy.Core;
-using BDDfy.Scanners.StepScanners.ExecutableAttribute;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-
-namespace BDDfy.ExecutableAttributes
-{
-    [TestClass]
-    public class NonCompliantMethodNamesWithExecutableAttributes
-    {
-        [TestMethod]
-        public void ShouldBeAbleToRunScenariosWithNonCompliantMethodNames()
-        {
-            this.BDDfy();
-        }
-
-        void GivenSomeMethodsDoNotComplyWithBDDfyMethodNameConventions()
-        {
-        }
-
-        void WhenExecutableAttributeIsApplied()
-        {
-        }
-
-        [Executable(ExecutionOrder.Assertion, "BDDfy can pickup the steps")]
-        void BDDfyCanPickupTheSteps()
-        {
-        }
-
-        [Executable(ExecutionOrder.ConsecutiveAssertion, "which are decorated with the attribute")]
-        void ThatAreDecoratedWithTheAttributes()
-        {
-        }
-    }
-}
-
- -The only difference between this class and the previous implementation is the addition of the `ExecutableAttribute` on the last two methods. Now if you run the test you can see that these two methods have been picked up and run as part of scenario: - -![Executable attribute](/img/BDDfy/executable-attributes/NonCompliantMethodNamesWithExecutableAttributes.jpg) - -It is also worth mentioning that the 'Given' and 'When' steps were picked up too using method name conventions! BDDfy runs the Method Name Convention and `ExecutableAttribute` scanners in a pipeline (using [Chain of Responsibility](http://en.wikipedia.org/wiki/Chain-of-responsibility_pattern)) which means that for a method to be considered a step it has to either match the naming conventions or be decorated with `Executable` attribute. - -If a method matches both criteria then the one decorated with `ExecutableAttribute` wins. For example let's change the 'When' step to start with 'Then' (not that it makes sense; but for demonstration purposes only): - -
-using BDDfy.Core;
-using BDDfy.Scanners.StepScanners.ExecutableAttribute;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-
-namespace BDDfy.ExecutableAttributes
-{
-    [TestClass]
-    public class ExecutableAttributesOverridingTheNamingConvention
-    {
-        [TestMethod]
-        public void ShouldBeAbleToRunScenariosWithNonCompliantMethodNames()
-        {
-            this.BDDfy();
-        }
-
-        void GivenSomeMethodsDoNotComplyWithBDDfyMethodNameConventions()
-        {
-        }
-
-        [Executable(ExecutionOrder.Transition, "When the methods are decorated with ExecutableAttributes")]
-        void ThenExecutableAttributeIsApplied()
-        {
-        }
-
-        [Executable(ExecutionOrder.Assertion, "BDDfy can pickup the steps")]
-        void BDDfyCanPickupTheSteps()
-        {
-        }
-
-        [Executable(ExecutionOrder.ConsecutiveAssertion, "which are decorated with the attribute")]
-        void ThatAreDecoratedWithTheAttributes()
-        {
-        }
-    }
-}
-
- -Using Method Name Conventions this method would be picked up as a 'Then' step; but since it is decorated with `ExecutableAttribute` with `ExecutionOrder.Transition` (which translates to 'When') it is run as a 'When' step and gets the title specified in the attribute instead of the one driven from the method name by convention. - -![Executable attribute overriding the method name convention](/img/BDDfy/executable-attributes/ExecutableAttributesOverridingTheNamingConvention.jpg) - -##But dude, ExecutableAttribute is too technical -Fair enough. That is more of an implementation detail plus an extension point that you should not normally care about. For that reason BDDfy comes with a set of predefined subclasses of `ExecutableAttribute` which are easier to use: `Given`, `AndGiven`, `When`, `AndWhen`, `Then` and `AndThen`. These attributes have default constructors that allow you to set a method as a step without having to provide a title in which case the title will be driven by the method name. They also have a constructor that allows you the specify the title which will override the default convention. Let's see that in action. Changing the last example to use these attributes: - -
-using BDDfy.Core;
-using BDDfy.Scanners.StepScanners.ExecutableAttribute;
-using BDDfy.Scanners.StepScanners.ExecutableAttribute.GwtAttributes;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-
-namespace BDDfy.ExecutableAttributes
-{
-    [TestClass]
-    public class NonCompliantMethodNamesWithGwtAttributes
-    {
-        [TestMethod]
-        public void ShouldBeAbleToRunScenariosWithNonCompliantMethodNames()
-        {
-            this.BDDfy("Non compliant method names with GWT attributes");
-        }
-
-        void GivenSomeMethodsDoNotComplyWithBDDfyMethodNameConventions()
-        {
-        }
-
-        void WhenExecutableAttributeIsApplied()
-        {
-        }
-
-        [Then]
-        void BDDfyCanPickupTheSteps()
-        {
-        }
-
-        [AndThen("which are decorated with the Given, AndGiven, When, AndWhen, Then or AndThen attributes ")]
-        void ThatAreDecoratedWithTheAttributes()
-        {
-        }
-    }
-}
-
- -The only change here was to replace the `ExecutableAttribute` usage with `Then` and `AndThen` attributes. And here is the report: - -![Using Given, When, Then attributes](/img/BDDfy/executable-attributes/NonCompliantMethodNamesWithGwtAttributes.jpg) - -To spice things up a bit I am also overriding the scenario name. This is only to show that you can always override scenario title regardless of your preferred BDDfy API/mode. - -##Can I exclude a method from scan? -Just like there are cases when your step method name does not comply with conventions there may be cases where you have a non-step method that just happens to comply with conventions. Consider the following example: - -
-using BDDfy.Core;
-using BDDfy.Scanners.StepScanners.ExecutableAttribute;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-
-namespace BDDfy.ExecutableAttributes
-{
-    [TestClass]
-    public class ExcludingMethodsFromScan
-    {
-        [TestMethod]
-        public void ShouldBeAbleToRunScenariosWithNonCompliantMethodNames()
-        {
-            this.BDDfy();
-        }
-
-        void GivenSomeMethodsComplyWithBDDfyMethodNameConventions()
-        {
-        }
-
-        void AndGivenTheyAreNotRealSteps()
-        {
-        }
-
-        void WhenIgnoreStepAttributeIsApplied()
-        {
-            WhenEzuelaIsNotSpelledLikeThisDude();
-        }
-
-        void WhenEzuelaIsNotSpelledLikeThisDude()
-        {
-        }
-
-        void ThenBDDfyIgnoresTheMethod()
-        {
-        }
-    }
-}
-
- -Ok, admittedly that is a silly example; but it shows my point :o) - -There is a method called `WhenEzuelaIsNotSpelledLikeThisDude` which matches BDDfy's method name conventions. By default this method would be picked up as a step and run by BDDfy which is not what you want because it is there to support other methods in your scenario and is not a step. In cases like this, if you do not want to rename your method, you can use `IgnoreStepAttribute` like below: - -
-using BDDfy.Core;
-using BDDfy.Scanners.StepScanners;
-using BDDfy.Scanners.StepScanners.ExecutableAttribute;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-
-namespace BDDfy.ExecutableAttributes
-{
-    [TestClass]
-    public class ExcludingMethodsFromScan
-    {
-        [TestMethod]
-        public void ShouldBeAbleToRunScenariosWithNonCompliantMethodNames()
-        {
-            this.BDDfy();
-        }
-
-        void GivenSomeMethodsComplyWithBDDfyMethodNameConventions()
-        {
-        }
-
-        void AndGivenTheyAreNotRealSteps()
-        {
-        }
-
-        void WhenIgnoreStepAttributeIsApplied()
-        {
-            WhenEzuelaIsNotSpelledLikeThisDude();
-        }
-
-        [IgnoreStep]
-        void WhenEzuelaIsNotSpelledLikeThisDude()
-        {
-        }
-
-        void ThenBDDfyIgnoresTheMethod()
-        {
-        }
-    }
-}
-
- -I just had to decorate the method with the attribute and now when I run the test that method is no longer picked up and run as a step which is my desired behavior. - -![IgnoreStepAttribute](/img/BDDfy/executable-attributes/IgnoreStepAttribute.jpg) - -This is not necessarily related to the `Executable` attribute as such and is part of the Reflective Scanner's logic which applies to both method name conventions and executable attributes. - -##How to create your own dialect -If you want to use another syntax for your BDD behaviors because you do not like Given, When, Then or because you are writing low-level tests that do not quite fit into the GWT model you can create your own syntax easily. Near the end of this series I am writing a few posts dedicated to BDDfy extension points and how you can override and/or extend the framework easily. So I will just provide a small hint about this here and leave the full story for later. - -In this running mode the only thing BDDfy cares about is the `Executable` attribute; so you can very easily subclass it as I have done with the abovementioned attributes and create a new dialect and it will just work. For your reference this is the implementation of a few of the out of the box attributes: - -**[GivenAttribute](https://github.com/TestStack/TestStack.BDDfy/blob/master/TestStack.BDDfy/Scanners/StepScanners/ExecutableAttribute/GwtAttributes/GivenAttribute.cs)** -
-public class GivenAttribute : ExecutableAttribute
-{
-    public GivenAttribute() : this(null) { }
-    public GivenAttribute(string stepTitle) : base(Core.ExecutionOrder.SetupState, stepTitle) { }
-}
-
- -**[AndGivenAttibute](https://github.com/TestStack/TestStack.BDDfy/blob/master/TestStack.BDDfy/Scanners/StepScanners/ExecutableAttribute/GwtAttributes/AndGivenAttribute.cs)** -
-public class AndGivenAttribute : ExecutableAttribute
-{
-    public AndGivenAttribute() : this(null) { }
-    public AndGivenAttribute(string stepTitle) : base(Core.ExecutionOrder.ConsecutiveSetupState, stepTitle) { }
-}
-
- -**[WhenAttribute](https://github.com/TestStack/TestStack.BDDfy/blob/master/TestStack.BDDfy/Scanners/StepScanners/ExecutableAttribute/GwtAttributes/WhenAttribute.cs)** -
-public class WhenAttribute : ExecutableAttribute
-{
-    public WhenAttribute() : this(null) { }
-    public WhenAttribute(string stepTitle) : base(Core.ExecutionOrder.Transition, stepTitle) { }
-}
-
- -It is very easy to implement your own attribute and create your own dialect with BDDfy. You can also very easily override the existing Method Name Conventions to create a new dialect for conventions; but that is a matter of another post :) - - - - [10]: http://hg.mehdi-khalili.com/BDDfy/src/83fd2f4566c4/BDDfy/Scanners/StepScanners/ExecutableAttribute/GwtAttributes/GivenAttribute.cs - [11]: http://hg.mehdi-khalili.com/BDDfy/src/83fd2f4566c4/BDDfy/Scanners/StepScanners/ExecutableAttribute/GwtAttributes/AndGivenAttribute.cs - [12]: http://hg.mehdi-khalili.com/BDDfy/src/83fd2f4566c4/BDDfy/Scanners/StepScanners/ExecutableAttribute/GwtAttributes/WhenAttribute.cs diff --git a/docs/Usage/FluentAPI.md b/docs/Usage/FluentAPI.md deleted file mode 100644 index fa14c9b4..00000000 --- a/docs/Usage/FluentAPI.md +++ /dev/null @@ -1,185 +0,0 @@ -# Fluent API - -BDDfy can scan your tests in one of two ways: using Reflective API and Fluent API. Reflective API uses some hints to scan your classes. These hints are provided through [Method Name Conventions](/BDDfy/method-name-conventions.html) and/or `[ExecutableAttribute][/BDDfy/executable-attributes.html]` which we have discussed before. For this post we will concentrate on Fluent API. - -I just thought I would share a bit of history with you first. I had just released BDDfy V0.5 and the API had kinda settled. So I thought I'd write an [introductory article on CodeProject](http://www.codeproject.com/Articles/205381/Introduction-to-bddify-A-Simple-to-Use-and-Extend) to promote the framework. On the top of article I said '*BDDfy is very extensible. In fact, BDDfy core barely has any logic in it. It delegates all its responsibilities to its extensions*'. Then I thought that just claiming a framework is extensible does not mean anything if I cannot provide a sample for it. That is why I wrote the Fluent API as I was writing that article to prove it to myself that BDDfy is highly extensible and also to provide an example of that. Well, I started it as an extensibility example; but then I liked and felt the need for it and baked into the framework. Today it is no longer a sample and in fact it is even more popular than Reflective mode!! - -##Fluent API -Fluent API of BDDfy does not really require much explanation as it is quite fluent ;-) So instead of trying to explain to you how it works I will just provide an example. - -In the Method Name Conventions post I wrote a scenario called 'BDDfyRocks' which I repeat here for your convenience: - -
-public class BDDfyRocks
-{
-    [Test]
-    public void ShouldBeAbleToBDDfyMyTestsVeryEasily()
-    {
-        this.BDDfy();
-    }
-
-    void GivenIHaveNotUsedBDDfyBefore()
-    {
-    }
-
-    void WhenIAmIntroducedToTheFramework()
-    {
-    }
-
-    void ThenILikeItAndStartUsingIt()
-    {
-    }
-}
-
- -And then we expanded that scenario to the second one shown below: - -
-public class BDDfyRocksEvenForBddNewbies
-{
-    [Test]
-    public void ShouldBeAbleToBDDfyMyTestsVeryEasily()
-    {
-        this.BDDfy();
-    }
-
-    void GivenIAmNewToBdd()
-    {
-    }
-
-    void AndGivenIHaveNotUsedBDDfyBefore()
-    {
-    }
-
-    void WhenIAmIntroducedToTheFramework()
-    {
-    }
-
-    void ThenILikeItAndStartUsingIt()
-    {
-    }
-
-    void AndILearnBddThroughBDDfy()
-    {
-    }
-}
-
- -Let's rewrite these two scenarios using Fluent API: - -
-using NUnit.Framework;
-
-namespace BDDfy.FluentApi
-{
-    public class BDDfySeriouslyRocks
-    {
-        [Test]
-        public void BDDfyRocks()
-        {
-            this.Given(_ => GivenIHaveNotUsedBDDfyBefore())
-                .When(_ => WhenIAmIntroducedToTheFramework())
-                .Then(_ => ThenILikeItAndStartUsingIt())
-                .BDDfy();
-        }
-
-        [Test]
-        public void BDDfyEvenRocksForBddNewbies()
-        {
-            this.Given(_ => GivenIAmNewToBdd())
-                    .And(_ => AndIHaveNotUsedBDDfyBefore())
-                .When(_ => WhenIAmIntroducedToTheFramework())
-                .Then(_ => ThenILikeItAndStartUsingIt())
-                    .And(_ => AndILearnBddThroughBDDfy())
-                .BDDfy();
-        }
-
-        void GivenIHaveNotUsedBDDfyBefore()
-        {
-        }
-
-        void GivenIAmNewToBdd()
-        {
-        }
-
-        void AndIHaveNotUsedBDDfyBefore()
-        {
-        }
-
-        void WhenIAmIntroducedToTheFramework()
-        {
-        }
-
-        void ThenILikeItAndStartUsingIt()
-        {
-        }
-
-        void AndILearnBddThroughBDDfy()
-        {
-        }
-    }
-}
-
- -This class has two test methods each representing one of the scenarios. The reports generated by these tests are exactly the same as those shown in the [Method Name Conventions](/BDDfy/method-name-conventions.html) post. - -There are a few important differences in implementation as follows: - - - In Reflective API the only thing you need to call is `this.BDDfy();` or one of its overloads that accepts the story type argument and/or the custom scenario title (and then BDDfy will find your steps using conventions or attributes). In the Fluent API you should explicitly specify all your steps before calling the `BDDfy` method. - - When using Reflective API the scenario name is driven by the name of the class because each class represents a scenario. In Fluent API, however, a class usually represents a story (or collection of related scenarios in the absence of a story) and scenarios are represented by methods. That is why while porting the sample to use Fluent API I renamed my scenario method names to match the class name that represented the scenario in the source sample. This is to ensure that I will get the same title for my scenarios after using Fluent API. - - In Reflective API BDDfy would pick up any combination of scenario steps by method name conventions and `ExecutableAttribute`; but in Fluent API mode you are in complete control. This means that regardless of what your method names are or whether they are decorated with `ExecutableAttribute` or not the steps you specify using the Fluent API will run by BDDfy. Likewise if there is a method that complies with method name conventions and/or is decorated by `ExecutableAttribute` (or one of its derivatives) but is not specified in your Fluent API call it is not going to be picked up by the framework. Reflective and Fluent modes run in isolation of each other and you choose the mode by the way you call the `BDDfy` method. - - In Reflective mode the method name starting with 'AndGiven' and 'AndWhen' will result into steps starting with 'And': the framework knows that you have provided the extra 'Given' and 'When' words only to comply with its conventions and as such drops them from the reports. In the Fluent API your step titles are derived directly from your method name. So when porting the example from using Method Name Convention to Fluent API I renamed `AndGivenIHaveNotUsedBDDfyBefore` to `AndIHaveNotUsedBDDfyBefore` to avoid getting 'And given' in my report. - - You notice that I removed two methods while porting the code to use Fluent API: `WhenIAmIntroducedToTheFramework` and `ThenILikeItAndStartUsingIt`. These two methods were repeated in each scenario; but I ported all scenarios and methods to the same class; so we can avoid duplication. Well, in all fairness the same could be achieved in the Reflective mode through inheritance where the shared logic lives in a base class that other scenarios subclass; but I think the reuse is kinda more natural in the Fluent mode. - - If you use R#, in Reflective mode if you write your steps as private methods you are going to get R# warning for unused methods because R# does not have any idea about the reflection magic going behind the scenes. Using Fluent API because you explicitly call the methods you no longer get the R# warning because you are using the methods. In order to avoid the warning in Reflective mode you may define your methods as protected or public to avoid the warnings. - -###Adding Story -Out of the box, there is only one way to [specify your Story](/BDDfy/story.html) and to associate it with scenarios and that is using `StoryAttribute`. This is the same for Reflective and Fluent modes. - -Let's add story to the above example: - -
-using BDDfy.Core;
-using NUnit.Framework;
-
-namespace BDDfy.FluentApi
-{
-     [Story(
-        AsA = "As a .net programmer",
-        IWant = "I want to use BDDfy",
-        SoThat = "So that BDD becomes easy and fun")]
-    public class BDDfySeriouslyRocks
-    {
-        [Test]
-        public void BDDfyRocks()
-        {
-            this.Given(_ => GivenIHaveNotUsedBDDfyBefore())
-                .When(_ => WhenIAmIntroducedToTheFramework())
-                .Then(_ => ThenILikeItAndStartUsingIt())
-                .BDDfy();
-        }
-
-        // The rest is removed for brevity
-    }
-}
-
- -As mentioned in a previous post, to create a story you need to decorate a class with `StoryAttribute`. In the Fluent mode the story class is usually the same as the class that contains the scenarios because, unlike Reflective mode, a scenario does not necessarily map to a class and is usually implemented in a method. - -This of course has its pros and cons. The nice thing about this approach is that you can see an entire story in one file/class; at the same time that could be considered a disadvantage because some stories are rather big and have quite a few scenarios which will result into a big class. Again you do not have to put all the scenarios of a story in one class: that is just one option. - -Running the tests now will include the story title and narrative into console and html reports. - -##FAQ -These are some of the FAQs I have received for Fluent API: - -###Should I have my methods in the right order? -In the Reflective mode there is a situation where you have to put your methods in the right order and that is when you have more than one 'AndGiven' or 'AndWhen' or 'And' in which you case the 'and' parts are executed in the order they appear in the class. In the Fluent API that does not matter. The methods are executed in the order specified using the Fluent API. So it does not matter in what order they appear in the class. - -###How I can reuse some of the testing logic? -As mentioned above with Fluent API it is very easy to reuse the test logic across all scenarios of the same story because usually they are all in the same class. If the logic is not in the same class, you can still use inheritance or composition to compose a scenario. - -###Can my step methods be static or should they be instance methods? -BDDfy handles both cases. So feel free to use whatever makes sense. - - - [6]: http://www.mehdi-khalili.com/get/blogpictures/BDDfy-in-action/fluent-api/console-report-without-story.JPG diff --git a/docs/Usage/FluentApiInputParameters.md b/docs/Usage/FluentApiInputParameters.md deleted file mode 100644 index 072e41b4..00000000 --- a/docs/Usage/FluentApiInputParameters.md +++ /dev/null @@ -1,187 +0,0 @@ -# Fluent API Input Params - -In [the last post](/fluent-api.html) we discussed BDDfy's Fluent API and had a look at a very simple usage where we ported the example done using [Method Name Convention](/method-name-conventions.html) to use Fluent API. In this post we will discuss how you can provide input parameters to your step methods when using Fluent API. - -##Using input parameters -In order to specify your step methods in Fluent API you provide BDDfy with some method call lambda expressions. In the examples we have seen so far we only called methods that did not have any input parameters; but BDDfy also supports input parameters. BDDfy inspects the provided expression and [extracts the input parameters](http://www.mehdi-khalili.com/extracting-input-arguments-from-expressions) you have passed and when it comes the execution time it calls those methods using the provided inputs. Alright let's see this in action. The example this time will be about modeling [Alcohol Laws in Australia](http://en.wikipedia.org/wiki/Alcohol_laws_of_Australia). As usual the examples you see here are created to show you the API usage. - -Let's see what the code would look like using Fluent API without overriding the titles and injecting input parameters: - -
-using NUnit.Framework;
-
-namespace BDDfy.FluentApiInputParameters
-{
-    public class AlcoholLawsApplyToLicencedPremises
-    {
-        [Test]
-        public void AlcoholIsNotSoldToMinors()
-        {
-            this.Given(_ => GivenIWasBornOn01011998())
-                .When(_ => WhenIAskToBuyAlcoholInALicencedPremiseOn01012012())
-                .Then(_ => ThenIDoNotGetTheAlocohol())
-                    .And(_ => AndIAmWalkedOut())
-                .BDDfy();
-        }
-
-        private void AndIAmWalkedOut()
-        {
-        }
-
-        private void ThenIDoNotGetTheAlocohol()
-        {
-        }
-
-        private void WhenIAskToBuyAlcoholInALicencedPremiseOn01012012()
-        {
-        }
-
-        private void GivenIWasBornOn01011998()
-        {
-        }
-    }
-}
-
- -Hmmm, the method names are rather ugly and not very readable! How about the reports? - -![Ugly report from the first attempt](/img/BDDfy/fluent-api-input-params/first-attempt-ugly-report.JPG) - -The reports are a bit more readable due to spacing between words; but the dates are still cryptic. We can do better than that. Below I have added a new method to the same class in which I have overridden the default step title for the 'Given' and 'When' methods: - -
-[Test]
-public void AlcoholIsNotSoldToMinorsTake2()
-{
-    this.Given(_ => GivenIWasBornOn01011998(), "Given I was born on 01-01-1998")
-        .When(_ => WhenIAskToBuyAlcoholInALicencedPremiseOn01012012(), "When I ask to buy alcohol in a licenced permise on 01-01-2012")
-        .Then(_ => ThenIDoNotGetTheAlocohol())
-            .And(_ => AndIAmWalkedOut())
-        .BDDfy("Alcohol is not sold to minors");
-}
-
- -Please note that I also overrode the scenario title. This had to happen because I named my scenario method AlcoholIsNotSoldToMinorsTake2 which by default would result into scenario title 'Alcohol is not sold to minors take 2' which obviously is not what I want. So I overrode it to the title I'd be happy with. - -In this implementation the method names are still as unreadable as before; but the reports look a bit better as the dates are more readable: - -![Step titles are overridden](/img/BDDfy/fluent-api-input-params/step-titles-are-overridden.JPG) - -In this implementation the dates, that should be more like variables, are still part of my method names. This means that I cannot reuse the same method to write a test for happy path where for example someone over 18 years old can buy alcohol. So what can we do? Input parameters to the rescue. Let's change our methods to accept input parameters. Add the following code to the same class: - -
-[Test]
-public void AlcoholIsNotSoldToMinorsTake3()
-{
-    this.Given(_ => GivenIWasBornOn(new DateTime(1998, 1, 1)))
-        .When(_ => WhenIAskToBuyAlcoholInALicencedPremiseOn(new DateTime(2012, 1, 1)))
-        .Then(_ => ThenIDoNotGetTheAlocohol())
-            .And(_ => AndIAmWalkedOut())
-        .BDDfy("Alcohol is not sold to minors");
-}
-
-private void WhenIAskToBuyAlcoholInALicencedPremiseOn(DateTime occurrenceDate)
-{
-}
-
-private void GivenIWasBornOn(DateTime dateOfBirth)
-{
-}
-
- -Again I had to override the scenario title. This time I have implemented two methods that look exactly the same as my previous 'Given' and 'When' methods except that they accept the date as parameters. So in my scenario method I am providing the dates inline as input parameters. The code is now much more readable and the report looks like: - -![Using input parameters](/img/BDDfy/fluent-api-input-params/using-input-parameters.JPG) - -As you can see in the report the input parameters are ToStringed and appended to step titles. This implementation solved the problems mentioned above. BDDfy can see that you are passing some input parameters to your lambda expressions; so it extracts them out and uses them to generate a step title. In this particular case, due to using DateTime, the result is less than perfect because of the time element; but other primitives will result in a much nicer output. - -... but that is not a good excuse and I want my dates to look good too, I hear you say. You can of course override the custom title behavior by passing a custom title in, like we did before; but we also want the custom title to be input-parameter aware. In other words we want the title to be formed based on the provided parameters: - -
-[Test]
-public void AlcoholIsNotSoldToMinorsTake4()
-{
-    this.Given(_ => GivenIWasBornOn(new DateTime(1998, 1, 1)), "Given I was born on {0:dd-MMM-yyyy}")
-        .When(_ => WhenIAskToBuyAlcoholInALicencedPremiseOn(new DateTime(2012, 1, 1)), "When I ask to buy alcohol in a licenced premise on {0:dd-MMM-yyyy}")
-        .Then(_ => ThenIDoNotGetTheAlocohol())
-            .And(_ => AndIAmWalkedOut())
-        .BDDfy("Alcohol is not sold to minors");
-}
-
- -This time I have overridden the default title by providing a custom one; but the custom title has a placeholder for my input parameter which also accepts [string formatter](http://msdn.microsoft.com/en-us/library/8kb3ddd4(v=VS.100).aspx). The report looks like (this time I use the html report for a change): - -![Input parameter with string formatter](/img/BDDfy/fluent-api-input-params/input-parameter-with-string-formatter.JPG) - -The report this time is much more readable. I also used a date format that avoids confusion for American readers where 01-05-1998, for example, indicates 5th of January. The formatters are standard .Net formatters and this allows you to make your reports more readable when dealing with things like currency, date, time, decimal numbers and so on. It is worth highlighting that you do not necessarily have to provide a format string and can only use the placeholders. - -When you do not override the default title behavior BDDfy appends the input parameters at the end of the step title; but in some cases you want the parameter to appear in the middle of the title. For example assume I have a scenario where my 'Given' part should read as "Given I was born between 'May 1950' and 'June 1990'". If I wrote it as: - -
-this.Given(_ =>
-    GivenIWasBornBetween(
-        new DateTime(1950, 5, 1),
-        new DateTime(1990, 6, 1))
-
- -Then my title would be "Given I was born between 01/05/1950 12:00:00 AM, 01/06/1990 12:00:00 AM"!!! To get the result I wanted I would have to override my title as: - -
-this.Given(_ =>
-    GivenIWasBornBetween(
-        new DateTime(1950, 5, 1),
-        new DateTime(1990, 6, 1),
-    "Given I was born between '{0:MMMM yyyy}' and '{1:MMMM yyyy}'")
-
- -which gives me "Given I was born between 'May 1950' and 'June 1990'" including the quotes. - -So we can easily format our title using placeholders and formatters; but what if I do not want my input parameters to be shown in the report?!! There are cases where you want to provide input parameters to a method but do not want it to be included in the title. This is usually the case when you are reusing the same method, that takes input parameters, for several scenarios. - -
-[Test]
-public void AlcoholIsNotSoldToMinorsParametersNotShownInTheReportTake1()
-{
-    this.Given(_ => GivenIAmAMinor(new DateTime(1998, 1, 1)))
-        .When(_ => WhenIAskToBuyAlcoholInALicencedPremise())
-        .Then(_ => ThenIDoNotGetTheAlocohol())
-            .And(_ => AndIAmWalkedOut())
-        .BDDfy("Alcohol is not sold to minors");
-}
-
-private void GivenIAmAMinor(DateTime dateOfBirth)
-{
-}
-
-private void WhenIAskToBuyAlcoholInALicencedPremise()
-{
-}
-
- -In this example, for the 'Given' step I do not care when "*I*" was born but still want to pass the date of birth to the step method. If I ran this scenario as is I would get: - -![Not showing input parameters in the report - failed attempt](/img/BDDfy/fluent-api-input-params/avoiding-input-parameters-in-the-title-take-1.JPG) - -The 'Given' part does not look good at all as the date should not appear in the end. To remove the date from the end I will use another overload. The [overload's signature for the Given](https://github.com/TestStack/TestStack.BDDfy/blob/master/TestStack.BDDfy/Scanners/StepScanners/Fluent/FluentScanner.cs#L145) method looks like: - -
-Given(Expression> givenStep, bool includeInputsInStepTitle)
-
- -... and my changed scenario is: - -
-[Test]
-public void AlcoholIsNotSoldToMinorsParametersNotShownInTheReportTake2()
-{
-    this.Given(_ => GivenIAmAMinor(new DateTime(1998, 1, 1)), false)
-        .When(_ => WhenIAskToBuyAlcoholInALicencedPremise())
-        .Then(_ => ThenIDoNotGetTheAlocohol())
-            .And(_ => AndIAmWalkedOut())
-        .BDDfy("Alcohol is not sold to minors");
-}
-
- -which results into: - -![Not showing input parameters in the report](/img/BDDfy/fluent-api-input-params/avoiding-input-parameters-in-the-title-take-2.JPG) diff --git a/docs/Usage/MethodNameConventions.md b/docs/Usage/MethodNameConventions.md deleted file mode 100644 index 9ff1a2ab..00000000 --- a/docs/Usage/MethodNameConventions.md +++ /dev/null @@ -1,203 +0,0 @@ -# Method Name Conventions - -BDDfy can scan your tests in one of two ways: using Reflective API and Fluent API. Reflective API uses some hints to scan your classes and afterwards pretty much all the burden is on BDDfy's shoulders to find your steps, make sense of them and execute them in order. You can provide these hints in two ways: using method name conventions and/or attributes. For this post we will only concentrate on method name conventions. - -BDDfy uses a bit of magic to figure out what your scenario looks like and what it should execute. Despite the magic behind the scenes, using the BDDfy API is extremely simple - it boils down to 14 letters: - - this.BDDfy(); - -That is all the API you need to know to be able to use BDDfy in Reflective Mode. Well, that and a bit of knowledge about the conventions described below. - -##A class per scenario -In the reflective mode BDDfy associates each class with a scenario and you will basically end up with one class per scenario. - -Some developers like the Single Responsibility Principle forced nature of this approach and some do not. For those who think this is not very DRY (Don't Repeat Yourself) BDDfy allows you to take full control over this using the Fluent API. I personally use both approaches in every project because each has its pros and cons. - -A typical example of using method name convention looks like: - -
-using NUnit.Framework;
-
-namespace BDDfy.MethodNameConventions
-{
-    public class BDDfyRocks
-    {
-        [Test]
-        public void ShouldBeAbleToBDDfyMyTestsVeryEasily()
-        {
-            this.BDDfy();
-        }
-
-        void GivenIHaveNotUsedBDDfyBefore()
-        {
-        }
-
-        void WhenIAmIntroducedToTheFramework()
-        {
-        }
-
-        void ThenILikeItAndStartUsingIt()
-        {
-        }
-    }
-}
-
- -The only thing related to BDDfy in this class is this.BDDfy();!! - -As mentioned in the [index page](/BDDfy/index.html), BDDfy does not care what testing framework or test runner you use and it provides the same result for all of them. Here is the result of the test run using R#: - -![Resharper Result](/img/BDDfy/method-name-conventions/Resharper-result.JPG) - -Using that one line of code BDDfy was able to find out what your scenario title and test steps are and how to run them! It also provides the above console report and an html report as below: - -![Html report](/img/BDDfy/method-name-conventions/html-report.JPG) - -##How does BDDfy do all that? -When using the reflective mode, BDDfy scans your class (which is this you are calling BDDfy() on) and finds all the methods in it. It then adds all the methods which match its conventions to a list. After having gone through the class (and its base classes), it loops over the methods, executes them, and then generates a report. - -Here is the complete list of the out of the box conventions. The method name: - - * ending with "Context" is considered as a setup method (not reported). - * "Setup" is considered as as setup method (not reported). - * starting with "Given" is considered as a setup method (reported). - * starting with "AndGiven" is considered as a setup method that runs after Context, Setup and Given steps (reported). - * starting with "When" is considered as a transition method (reported). - * starting with "AndWhen" is considered as a transition method that runs after When steps (reported). - * starting with "Then" is considered as an asserting method (reported). - * starting with "And" is considered as an asserting method (reported). - * starting with "TearDown" is considered as a finally method which is run after all the other steps (not reported). - -Some of these special conventions will lead to the step not being reported. For example if your method name ends with the word 'Context' the step will be picked up by the framework and will be executed; but it will not be reported in console or html report. This was created on a request by a user; but I personally do not use this feature. If I need to setup my state I either do it in the 'Given' steps or in the class constructor if it is not directly related to the scenario state. - -It is worth mentioning that these conventions can be easily overridden if your needs require further customisation. - -BDDfy by default uses your scenario class name to generate a title for your scenario, however you can easily override this behaviour as we will see further down. - -##Another example -Let's expand on the example above and create something a bit more complex. My specification this time reads as: - -
-Given I am new to BDD
-  And I have not used BDDfy before
-When I am introduced to the framework
-Then I like it and I start using it
-  And I learn BDD through BDDfy
-
- -Not much difference to what I had before; but now I have two additional 'And' steps: one for 'Given' and one for 'Then'. Going by the conventions explained above you should implement this like below: - -
-using NUnit.Framework;
-
-namespace BDDfy.MethodNameConventions
-{
-    public class BDDfyRocksEvenForBddNewbies
-    {
-        [Test]
-        public void ShouldBeAbleToBDDfyMyTestsVeryEasily()
-        {
-            this.BDDfy();
-        }
-
-        void GivenIAmNewToBdd()
-        {
-        }
-
-        void AndGivenIHaveNotUsedBDDfyBefore()
-        {
-        }
-
-        void WhenIAmIntroducedToTheFramework()
-        {
-        }
-
-        void ThenILikeItAndStartUsingIt()
-        {
-        }
-
-        void AndILearnBddThroughBDDfy()
-        {
-        }
-    }
-}
-
- -Let's run this. This time I use [TD.Net](http://www.testdriven.net/) to show you the result from another test runner: - -![TD.Net result of the expanded test](/img/BDDfy/method-name-conventions/TDNet-expanded-test-result.JPG) - -So BDDfy was capable to find the 'AndGiven' method and turn it into an 'And' step that runs after the 'Given' step. The same goes for the 'And' method that is run after the 'Then' step. - -##How to use input arguments with method name conventions? -If your test requires input arguments there is a good chance you should be using the fluent API; that said BDDfy provides support for input arguments for the method name convention scanner too. - -In order to run the same scenario using different input arguments you need to create a scenario class which is not a test class. The scenario class should accept the input arguments through constructor parameters and then you may assign those to instance fields and use them in your step methods. You then will have another class, which will usually be your story class, to instantiate your scenario class using different input arguments and call BDDfy on the instance. It is hard to explain this and an example shows the usage better. - -BDDfy comes with two complete examples that showcase different most BDDfy features. You may install these samples through BDDfy.Samples.TicTacToe and BDDfy.Samples.ATM. This particular feature is used in the [TestStack.BDDfy.Samples](http://nuget.org/packages/TestStack.BDDfy.Samples) sample for testing the winner games. You may see the winner game scenario class [here](https://github.com/TestStack/TestStack.BDDfy/blob/master/TestStack.BDDfy.Samples/TicTacToe/WinnerGame.cs). For brevity I only include the class constructor here: - -
-public class WinnerGame : GameUnderTest
-{
-    private readonly string[] _firstRow;
-    private readonly string[] _secondRow;
-    private readonly string[] _thirdRow;
-    private readonly string _expectedWinner;
-
-    public WinnerGame(string[] firstRow, string[] secondRow, string[] thirdRow, string expectedWinner)
-    {
-        _firstRow = firstRow;
-        _secondRow = secondRow;
-        _thirdRow = thirdRow;
-        _expectedWinner = expectedWinner;
-    }
-
- -... and the code from the story that instantiates the class and runs it using different input arguments can be found [here](https://github.com/TestStack/TestStack.BDDfy/blob/master/TestStack.BDDfy.Samples/TicTacToe/TicTacToe.cs#L93). A bit of code copied from that codebase is shown below for your convenience: - -
-[Test]
-[TestCase("Vertical win in the right", new[] { X, O, X }, new[] { O, O, X }, new[] { O, X, X }, X)]
-[TestCase("Vertical win in the middle", new[] { N, X, O }, new[] { O, X, O }, new[] { O, X, X }, X)]
-[TestCase("Diagonal win", new[] { X, O, O }, new[] { X, O, X }, new[] { O, X, N }, O)]
-[TestCase("Horizontal win in the bottom", new[] { X, X, N }, new[] { X, O, X }, new[] { O, O, O }, O)]
-[TestCase("Horizontal win in the middle", new[] { X, O, O }, new[] { X, X, X }, new[] { O, O, X }, X)]
-[TestCase("Vertical win in the left", new[] { X, O, O }, new[] { X, O, X }, new[] { X, X, O }, X)]
-[TestCase("Horizontal win", new[] { X, X, X }, new[] { X, O, O }, new[] { O, O, X }, X)]
-public void WinnerGame(string title, string[] firstRow, string[] secondRow, string[] thirdRow, string expectedWinner)
-{
-    new WinnerGame(firstRow, secondRow, thirdRow, expectedWinner).BDDfy(title);
-}
-
- -This runs the WinnerGame test class as several scenarios with different inputs. The html report from the sample is shown below: - -![Tic Tac Toe html report](/img/BDDfy/method-name-conventions/tictactoe-html-result.JPG) - -The report has a story which I have not covered yet. - -So far we have been calling BDDfy() with no arguments so you may wonder what the title argument does. As you may guess from its name that argument overrides the scenario title. If we had not passed that argument in we would end up with 7 scenarios all titled 'Winner game' which is not what we want. So we pass in the title we want for the scenario based on the input arguments. - -##FAQ -These are some of the FAQs I have received for Method Name Conventions: - -#####Should I have my methods in the right order? -Ordinarily, no. BDDfy picks the methods based on the naming convention and regardless of where in the class they appear BDDfy runs and reports them in the right order. However, if you have multiple 'AndGiven', 'AndWhen', or 'And' steps you need to put these methods in the order that you want BDDfy to pick them up. - -If for some reason you are using both a Setup method and an xxxContext method to perform some setup then these will run in the order in which they are defined in your class. It is probably a better idea to refactor these into a single method if possible. - -#####How I can reuse some of the testing logic? -You may achieve that through scenario inheritance or composition as you would in your business logic code. - -When inheriting from a base class that has a few steps BDDfy picks the steps from your base classes as if they were in your scenario class. This is useful when you have several scenarios that share a few steps. This way you put the shared steps in the base class and subclass that in your scenario classes. - -Using composition you may put the actual logic in a separate class and use them from your scenario classes. If you are using composition then you may want to consider the fluent API because it does just what you want. I will discuss them in another post in near future. - -#####Why does not BDDfy pick up my base class methods? -Because you should define them either as public or protected. BDDfy ignores the base class methods with private access modifier. - -#####Can my step methods be static or should they be instance methods? -BDDfy handles both cases. So feel free to use whatever makes sense. - -#####Where can I setup my mocks or other bits not directly related to the scenario? -When unit testing you usually end up mocking a few interfaces and setting up a few things that are not necessarily related to the scenario under test, but are necessary for you to be able to test the scenario. I usually put this logic into the class constructor. If what you are setting up is directly related to the scenario then you should put the logic in your 'Given' step(s). diff --git a/docs/Usage/Reports.md b/docs/Usage/Reports.md deleted file mode 100644 index 0ea59b5b..00000000 --- a/docs/Usage/Reports.md +++ /dev/null @@ -1,121 +0,0 @@ -# Reports - -BDDfy provides a rich array of reports to choose from and is also very easy to extend if you want to add your own reports. The two main reports are the Console Report and the HTML Report and both of these are on by default, though you can turn them off if you want to. In addition there is a Markdown Report, and recently a Diagnostics Report using JSON has been added. Both of these are off by default. - -##The Reports -I am going to start with an overview of the different reports available in BDDfy, using the ATM sample, available in the [BDDfy source code](https://github.com/TestStack/TestStack.BDDfy/tree/master/Samples/TestStack.BDDfy.Samples/Atm), or on [NuGet][3]. - -###Console Report -The Console Report is what provides feedback in Visual Studio when you run your tests. If you run the tests with TestDriven.Net then you will see the output from all the tests in the output window. - -![BDDfy sample test driven output](/img/BDDfy/Customizing/bddfy-sample-test-driven-output.png) - -At the end of the report it will also provide a summary of how many tests passed, failed, or were skipped and how long the tests took to run. - -![BDDfy sample test driven summary output](/img/BDDfy/Customizing/bddfy-sample-test-driven-summary-output.png) - -If you run the tests in ReSharper then you see the output of each test individually when you select it in the Unit Test Sessions window. - -![BDDfy resharper success output](/img/BDDfy/Customizing/bddfy-sample-resharper-output.png) - -When the test passes, you just see the Scenario listed out, and its story if it has one. If the test fails, or is not implemented yet, then you will also see details alongside each step of which steps were executed and what their status was and an exception trace detailing the error information. - -![BDDfy resharper failure output](/img/BDDfy/Customizing/bddfy-sample-resharper-exception-output.png) - -###HTML Report -If you are practicing BDD, then you will probably be interested in living documentation. BDDfy can help with this with its HTML report, which dev teams can share with their customers to see the progress in a very user friendly and accessible way. Every time you run tests with BDDfy it creates an HTML report in the bin directory of the test project. The report has a summary at the top, listing out how many Stories/Scenarios have run, and the totals for each type of execution result. The report is interactive, and lets you expand and collapse individual stories and scenarios or all at once. The report is very customisable and you are able to change the header, description, and the location where the report is saved to. You can also add your own CSS and JavaScript files to really open up the customisation possibilities. - -![BDDfy HTML sample report](/img/BDDfy/Customizing/bddfy-sample-atm-html.png) - -###Markdown Report -The Markdown Report can be turned on using the BDDfy Configurator (more on that below). The report is written in the [GitHub Flavoured Markdown][9] format. Markdown is a really useful format for documenting (I write this blog in markdown). A possible use for this would be as part of efforts to generate documentation, which might be particularly useful for open source developers to generate wiki documents from their code, for example. - -The Markdown Report is output to the bin directory of the test project and is named BDDfy.md. The picture below shows the BDDfy.md file in the MarkPad markdown editor. The left pane shows the raw text view and the pane on the right shows how it would be displayed on a web page. - -![BDDfy markdown sample report](/img/BDDfy/Customizing/bddfy-sample-atm-markdown.png) - -###Diagnostics Report -The Diagnostics Report is the most recent addition to the BDDfy stable. It is also off by default and can be turned on using the BDDfy Configurator. In BDDfy we can measure how long every step took to execute and then aggregate that data to see how long each Scenario and Story took to execute. This is particularly useful information if you have long running tests, such as browser-based functional tests, and want to identify the parts of the test that are having the worst impact on performance. For example, is it particularly slow when interacting with the database, or is it perhaps the rendering of the web pages? - -The Diagnostics Report is created in the JSON format. This is useful if you want to load the data into another system, perhaps to persist test runs to compare performance over time. The Diagnostics Report is output to the bin directory of the test project and is named Diagnostics.json. Here is the output for the ATM tests. - - { - "Stories": - [ - { - "Name":"Account holder withdraws cash", - "Duration":8, - "Scenarios": - [ - { - "Name":"Account has insufficient fund", - "Duration":8, - "Steps": - [ - { - "Name":"Given the Account Balance is $10", - "Duration":1 - }, - { - "Name":"And the Card is valid", - "Duration":0 - }, - { - "Name":"And the machine contains enough money", - "Duration":0 - }, - { - "Name":"When the Account Holder requests $20", - "Duration":0 - }, - { - "Name":"Then the ATM should not dispense any Money", - "Duration":5 - }, - { - "Name":"And the ATM should say there are Insufficient Funds", - "Duration":0 - }, - { - "Name":"And the Account Balance should be $20", - "Duration":0 - }, - { - "Name":"And the Card should be returned", - "Duration":0 - } - ] - } - ] - } - ] - } - - -##Configuring Reports - -The Configurator class is the main configuration point for BDDfy and should be called before all your tests run if you are wanting to change the default behaviour. For example, in NUnit you could call it from the SetUpFixture. - -BDDfy implements components as processors in a pipeline (using the [Chain of Responsibility pattern][11]) and reports are just another type of processor. Processors can be switched on and off using the Configurator class by calling the Enable or Disable methods. As previously mentioned, the Console Report and the HTML Report are both on by default. If you don’t want them to run then you can disable them like this: - - Configurator.Processors.ConsoleReport.Disable(); - Configurator.BatchProcessors.HtmlReport.Disable(); - -Similarly, you can turn on the Markdown and Diagnostics reports: - - Configurator.BatchProcessors.MarkDownReport.Enable(); - Configurator.BatchProcessors.DiagnosticsReport.Enable(); - -While this is great if you want to turn a processor off for all the tests, it isn’t much help if you want to just turn it on or off for some of the tests. Fortunately, there is also the the RunsOn method, which allows you to enable or disable processors using a predicate. This allows a lot of flexibility, and you could even choose to combine predicates so that, for example, half the tests ran with the Console Report and the other half ran with the Markdown Report. - - Configurator.Processors.ConsoleReport - .RunsOn(scenario => scenario.GetType().Namespace.StartsWith("MyCompany.MyApp.Domain")); - Configurator.Processors.MarkdownReport - .RunsOn(scenario => !scenario.GetType().Namespace.StartsWith("MyCompany.MyApp.Domain")); - -###Getting reports without running the tests -Having processors run in a pipeline leads to some interesting possibilities. One that I particularly like is that you can get all of the reports without actually running the tests. To do this you just need to turn off the TestRunner processor. The reports will still be generated, the only difference is that they will have a status of Not Executed! - - Configurator.Processors.TestRunner.Disable(); - -This is really useful when you want to print out the reports as documentation but don’t want to have to wait for the tests to run. diff --git a/docs/Usage/Story.md b/docs/Usage/Story.md deleted file mode 100644 index 67004914..00000000 --- a/docs/Usage/Story.md +++ /dev/null @@ -1,166 +0,0 @@ -# Story -In this post we will discuss how you can add story support to your BDD behaviors. As mentioned before and as we saw in the post about [Method Name Conventions](/BDDfy/MethodNameConventions.html) BDDfy does not force you to use stories. This could be quite useful for teams that do not work in an Agile environment. Forcing developers to come up with a story definition, while I believe is useful in many cases, could be less than optimal in some situations. For this reason you can `BDDfy` a scenario without associating it with a story; but that is more of an exception than a rule. So let's see how you can create stories and associate them with some scenarios. - -##How to create a story definition? -In BDDfy for everything you want to do there are several options; there is one exception to this and that is defining stories. There is only one way to define a story and it is quite simple: to define a story all you need to do is to decorate a class, any class anywhere in your solution, with a `StoryAttribute`. Doing so creates a story that you can then associate with your scenarios. Here is an example of a story: - -
-namespace BDDfy.Story
-{
-    [Story(
-        AsA = "As a .net programmer",
-        IWant = "I want to use BDDfy",
-        SoThat = "So that BDD becomes easy and fun")]
-    public class BDDfyRocks
-    {
-    }
-}
-
- -All I have here is a class decorated with a `Story` attribute. By decorating this class you have setup your story metadata once and forever so you will not have to repeat this info for every scenario. - -##So how do I associate a story with a scenario? -There are two ways to achieve this: - -###1. Let BDDfy find the association! -BDDfy can associate a story with a scenario if the scenario is BDDfied in a method defined in the story class. - -Let's write a scenario: - -
-namespace BDDfy.Story
-{
-    public class ShouldBeAbleToBDDfyMyTestsVeryEasily
-    {
-        void GivenIHaveNotUsedBDDfyBefore()
-        {
-        }
-
-        void WhenIAmIntroducedToTheFramework()
-        {
-        }
-
-        void ThenILikeItAndStartUsingIt()
-        {
-        }
-    }
-}
-
- -Please note that there is nothing related to BDDfy in this class. It is just a Plain Old C# Class which will eventually have some assertions in it. I can then BDDfy this scenario from my story class like: - -
-using BDDfy.Core;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-
-namespace BDDfy.Story
-{
-    [TestClass]
-    [Story(
-        AsA = "As a .net programmer",
-        IWant = "I want to use BDDfy",
-        SoThat = "So that BDD becomes easy and fun")]
-    public class BDDfyRocks
-    {
-        [TestMethod]
-        public void LetBDDfyFindTheStory()
-        {
-            new ShouldBeAbleToBDDfyMyTestsVeryEasily().BDDfy();
-        }
-    }
-}
-
- -There are a few changes here: - - - I added MSTest and BDDfy namespaces on the top. - - Decorated the story class with TestClass. This is an MSTest requirement. - - Created a new method which is my scenario and instantiated and bddified my scenario from within the method. - -Let's run our only test with R#: - -![Let BDDfy find the story](/img/BDDfy/story/let-BDDfy-find-the-story.JPG) - -If you compare this to the similar test we ran in the previous post you notice that this report shows a story on the top. The story details are picked up from the `StoryAttribute` on the class. - -And as you would expect the story details will appear in the html report too: - -![Html report with story](/img/BDDfy/story/separate-story-html-report.JPG) - -In the html report scenarios will be categorized by their stories. You can also expand or collapse them by clicking on them or by clicking on the expand all and collapse all which will expand and collapse them all respectively. - -... but how does BDDfy know how to associate the story with the scenario? At runtime BDDfy walks up the stack trace until it finds your test method and then finds the declaring class and checks to see if it is decorated with a `StoryAttribute` and if yes it associates the two. This brings us to the next approach of associating the stories and scenarios which is the recommended approach; but before going further I would like to ask you to read [this article](http://www.mehdi-khalili.com/that-tricky-stacktrace) about the intricacy of stack trace. I will wait here until you read that. - -Read it?! At runtime JIT may decide to flatten a few method calls and for that reason BDDfy may or may not be able to find your story class. Basically if you are running or intending to ever run your tests in release mode then you must use the second approach. - -###2. Tell BDDfy which story to use! -If you may run your tests in release mode, to avoid disappointment, you may want to explicitly associate a story with a scenario. This approach has some other advantages that I will explain shortly. - -In order to specify the story you should use an overload of `BDDfy` method which accepts a type argument for story. Here is the same example but using this overload: - -
-using BDDfy.Core;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-
-namespace BDDfy.Story
-{
-    [TestClass]
-    [Story(
-        AsA = "As a .net programmer",
-        IWant = "I want to use BDDfy",
-        SoThat = "So that BDD becomes easy and fun")]
-    public class BDDfyRocks
-    {
-        [TestMethod]
-        public void TellBDDfyWhatStoryToUse()
-        {
-            new ShouldBeAbleToBDDfyMyTestsVeryEasily().BDDfy<BDDfyRocks>();
-        }
-    }
-}
-
-
- -The only difference here is that I am passing `BDDfyRocks` type as a type argument to the `BDDfy()` method. This runs the very same steps and provides the very same report as we saw above; except that this method is guaranteed to find the story regardless of your build configuration or CPU architecture. - -##How can I override the story title? -By default BDDfy turns your story class name into the title for the story which appears in the reports. For example `BDDfyRocks` is turned into 'BDDfy rocks'. For what it is worth, the same logic is used to drive scenario and step titles. - -In the previous post we overrode a scenario title by passing the custom title into the `BDDfy()` method; but how can we override the story title? It is very simple: `StoryAttribute` has a `Title` property that you can set. If you leave that property alone BDDfy uses your story class name for the title; but if you set it, that value is used instead. - -As an example to override the title of the `BDDfyRocks` story we can set the title as follows: - -
-[Story(
-   Title = "Setting the story title is very easy",
-   AsA = "As a .net programmer",
-   IWant = "I want to use BDDfy",
-   SoThat = "So that BDD becomes easy and fun")]
-public class BDDfyRocks
-{
-}
-
- -##How can I reuse the same story for scenarios in different projects? -This is the only question I get asked every now and then about using stories. This usually happens when there are more than one test project in the solution and two tests/behaviors in two different projects happen to be related to the same story. This is where the second approach shines. When specifying the story in the `BDDfy()` the framework does not really care whether your scenario is being run within the story or is in the same class or in the same project. It is happy as long as it can see the story (which means as long as your code compiles). - -As an example the same scenario above could be written as (assuming that `AScenarioRunFromAnotherProject` lives in a different project): - -
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-
-namespace BDDfy.Story
-{
-    [TestClass]
-    public class AScenarioRunFromAnotherProject
-    {
-        [TestMethod]
-        public void TellBDDfyWhatStoryToUse()
-        {
-            new ShouldBeAbleToBDDfyMyTestsVeryEasily().BDDfy<BDDfyRocks>();
-        }
-    }
-}
-
- -This works the exact same way as if the story is defined in the same project or on the same class. diff --git a/docs/index.md b/docs/index.md deleted file mode 100644 index 8bc37c81..00000000 --- a/docs/index.md +++ /dev/null @@ -1,757 +0,0 @@ -BDDfy (pronounced B D Defy) is the simplest BDD framework for .Net EVER! The name comes from the fact that it allows you to turn your tests into BDD behaviors simply. - -A few quick facts about BDDfy: - - - It can run with any testing framework. Actually you don't have to use a testing framework at all. You can just apply it on your POCO (test) classes! - - It does not need a separate test runner. You can use your runner of choice. For example, you can write your BDDfy tests using NUnit and run them using NUnit console or GUI runner, Resharper or TD.Net and regardless of the runner, you will get the same result. - - It can run standalone scenarios. In other words, although BDDfy supports stories, you do not necessarily have to have or make up a story to use it. This is useful for developers who work in non-Agile environments but would like to get some decent testing experience. - - You can use underscored or pascal or camel cased method names for your steps. - - You do not have to explain your scenarios or stories or steps in string, but you can if you need full control over what gets printed into console and HTML reports. - - BDDfy is very extensible: it's core barely has any logic in it and it delegates all it's responsibilities to it's extensions all of which are configurable; e.g. if you don't like the reports it generates, you can write your custom reporter in a few lines of code. - -Using BDDfy, it is easier to switch to BDD. So if you are on a project with a couple of hundred tests already written and you think using BDD could make your tests more valuable, then BDDfy can help you with that. You are still going to need to make some changes; but hopefully they will be minimal. - -##Installation -To use BDDfy: - - - Install NuGet if you have not already. - - Go to 'Tools', 'Library Package Manager', and click 'Package Manager Console'. - - In the console, type `Install-Package TestStack.BDDfy` and enter. - -This adds BDDfy assembly and its dependencies to your test project. If this is the first time you are using BDDfy you may want to check out the samples on NuGet. Just run `Install-Package TestStack.BDDfy.Samples` and it will load two fully working samples to your project. - -##Usage -Let's see BDDfy in action. I am going to use [Dan North's ATM sample](http://dannorth.net/introducing-bdd/) for this. I will copy his sample here for your convenience: - -
-Story: Account Holder withdraws cash
-
-As an Account Holder
-I want to withdraw cash from an ATM
-So that I can get money when the bank is closed
-
-Scenario 1: Account has sufficient funds
-Given the account balance is $100
-  And the card is valid
-  And the machine contains enough money
-When the Account Holder requests $20
-Then the ATM should dispense $20
-  And the account balance should be $80
- And the card should be returned
-
-Scenario 2: Account has insufficient funds
-Given the account balance is $10
-  And the card is valid
-  And the machine contains enough money
-When the Account Holder requests $20
-Then the ATM should not dispense any money
-  And the ATM should say there are insufficient funds
-  And the account balance should be $10
-  And the card should be returned
-
-Scenario 3: Card has been disabled
-Given the card is disabled
-When the Account Holder requests $20
-Then the ATM should retain the card
-  And the ATM should say the card has been retained
-
- -In order to add BDDfy library to your test project: - - - In Visual Studio go to 'Tools', 'Library Package Manager', and click 'Package Manager Console'. - - In the console, type `Install-Package TestStack.BDDfy` and enter. - -This installs BDDfy on your project. As part of installation, BDDfy copies a file called 'BDDfy.ReadMe.txt' in your project root folder. This file explains a bit about how BDDfy works as well as some of its conventions. - -I will start with the last scenario for this sample because it is simpler than other scenarios and we can focus more on BDDfy than on the scenario's implementation: - - using System; - using Microsoft.VisualStudio.TestTools.UnitTesting; - using TestStack.BDDfy; - - namespace BDDfy.Samples.Atm - { - [TestClass] - public class CardHasBeenDisabled - { - void GivenTheCardIsDisabled() - { - throw new NotImplementedException(); - } - - void WhenTheAccountHolderRequestsMoney() - { - } - - void ThenTheAtmShouldRetainTheCard() - { - } - - void AndTheAtmShouldSayTheCardHasBeenRetained() - { - } - - [TestMethod] - public void Execute() - { - this.BDDfy(); - } - } - } - -This class represents our scenario and has one test method called Execute (it can be called anything). Inside this method, I have one line of code that calls BDDfy extension method on the instance. Let's run this test to see what happens. I am using ReSharper test runner to run the test: - -![Not Implemented Method](/img/BDDfy/not-implemented-method.png) - -*Figure 1: CardHasBeenDisabled console report before the scenario is implemented* - -That is the console report BDDfy generates. Note that BDDfy tells you that the 'Given' step has not been implemented yet and the other steps were not executed. - -By default, BDDfy also generates an HTML report called 'BDDfy.Html' in your project's output folder: - -![Not Implemented Method](/img/BDDfy/not-implemented-method-html.png) - -*Figure 2: CardHasBeenDisabled Html report before the scenario is implemented* - -HTML report shows the summary on the top and the details on the bottom. If you click on scenarios, it also shows you the steps of that scenario along with the step result (and in case of an exception, the stack trace). You have a lot of control over HTML report and can customize a lot of things. You can also inject your own custom css and Javascript to get full control over the styling too. - -
-Note: As indicated in HTML and console reports, 'Given' step was unsuccessful due to the exception. When there is an exception in 'Given' or 'When' steps BDDfy will not run the remaining steps. It is shown in the console report with '[Not Executed]' in front of steps and in the HTML report with 'Not Executed' icon. This is because if your 'Given' or 'When' steps fail, there is no reason to run other steps. This rule does not apply to asserting steps (i.e. 'Then' parts) which means that you could have three asserting steps with one of them failing and the other two passing. In this case, BDDfy runs all the steps and shows you which of your assertions failed.
- -###Method naming conventions in reflective API -BDDfy uses reflection to scan your classes for steps. In this mode, known as reflective mode, it has two ways of finding a step: using attributes and method name conventions. The following is the list of method name conventions: - - - Method name ending with `Context` is considered a setup method but doesn't get shown in the reports - - Method name equaling `Setup` is a setup method but doesn't get shown in in the reports - - Method name starting with `Given` is a setup step that gets shown in the reports - - Method name starting with `AndGiven` and 'And_given_' are considered setup steps running after 'Given' steps which is reported. - - Method name starting with `When` is considered a state transition step and is reported - - Method name starting with `AndWhen` and `And_when_` are considered state transition steps running after 'When' steps and is reported - - Method name starting with `Then` is an asserting step and is reported - - Method name starting with `And` and `AndThen` and `And_then_` are considered an asserting steps running after 'Then' step and is reported - - Method name starting with `TearDown` is considered as tear down method that is always run at the end but doesn't get shown in the reports. - -If you don't like Given When Then dialect you can write your own dialect and register it in a few lines of code. - -BDDfy uses method names to generate the step titles and uses the scenario class name to generate the scenario title. Ok, let's implement the steps: - - using Microsoft.VisualStudio.TestTools.UnitTesting; - using TestStack.BDDfy; - - namespace BDDfy.Samples.Atm - { - [TestClass] - public class CardHasBeenDisabled - { - private Card _card; - Atm _subject; - - void GivenTheCardIsDisabled() - { - _card = new Card(false, 100); - _subject = new Atm(100); - } - - void WhenTheAccountHolderRequestsMoney() - { - _subject.RequestMoney(_card, 20); - } - - void ThenTheAtmShouldRetainTheCard() - { - Assert.IsTrue(_subject.CardIsRetained); - } - - void AndTheAtmShouldSayTheCardHasBeenRetained() - { - Assert.AreEqual(DisplayMessage.CardIsRetained, _subject.Message); - } - - [TestMethod] - public void Execute() - { - this.BDDfy(); - } - } - } - -For the purpose of this article, I am going to provide you with the fully implemented domain class here. This is, of course, not the way you would do it in a real test first methodology: - - namespace BDDfy.Samples.Atm - { - public class Atm - { - public int ExistingCash { get; private set; } - - public Atm(int existingCash) - { - ExistingCash = existingCash; - } - - public void RequestMoney(Card card, int request) - { - if (!card.Enabled) - { - //CardIsRetained = true; - Message = DisplayMessage.CardIsRetained; - return; - } - - if (card.AccountBalance < request) - { - Message = DisplayMessage.InsufficientFunds; - return; - } - - DispenseValue = request; - card.AccountBalance -= request; - } - - public int DispenseValue { get; set; } - - public bool CardIsRetained { get; private set; } - - public DisplayMessage Message { get; private set; } - } - - public class Card - { - public int AccountBalance { get; set; } - private readonly bool _enabled; - - public Card(bool enabled, int accountBalance) - { - AccountBalance = accountBalance; - _enabled = enabled; - } - - public bool Enabled - { - get { return _enabled; } - } - } - - public enum DisplayMessage - { - None = 0, - CardIsRetained, - InsufficientFunds - } - } - -Let's run the test again: - -![Failed step console report](/img/BDDfy/failed-step-console.png) - -*Figure 3. CardHasBeenDisabled scenario with buggy implementation - console report* - -![Failed step console report](/img/BDDfy/failed-step-html.png) - -*Figure 4. CardHasBeenDisabled with buggy implementation - HTML report* - -As mentioned above, BDDfy does not stop the execution when there is an exception on your asserting steps. In this case, you can see that 'Then the atm should retain the card' step has failed; but BDDfy has run the next step and it shows you that it has passed. Of course, the scenario will be red until all its steps pass. - -Both console and HTML reports show that my scenario has failed. It seems like I have a bug in my Atm class. So I fix the bug (i.e. uncomment the only commented line in the Atm class) and run the test again and this time I get green result: - -![Passing test console report](/img/BDDfy/passing-test-console.png) - -*Figure 5. CardHasBeenDisabled green console report* - -![Passing test html report](/img/BDDfy/passing-test-html.png) - -*Figure 6. CardHasBeenDisabled green HTML report* - -###ExecutableAttribute in reflective API -Let's implement another scenario. This time, I will not bore you with the red and green phases: - - using Microsoft.VisualStudio.TestTools.UnitTesting; - using TestStack.BDDfy; - using TestStack.BDDfy.Scanners.StepScanners.ExecutableAttribute.GwtAttributes; - - namespace BDDfy.Samples.Atm - { - [TestClass] - public class AccountHasInsufficientFund - { - private Card _card; - private Atm _atm; - - // You can override step text using executable attributes - [Given("Given the account balance is $10")] - void GivenTheAccountBalanceIs10() - { - _card = new Card(true, 10); - } - - void AndGivenTheCardIsValid() - { - - } - - void AndGivenTheMachineContainsEnoughMoney() - { - _atm = new Atm(100); - } - - [When("When the account holder requests $20")] - void WhenTheAccountHolderRequests20() - { - _atm.RequestMoney(_card, 20); - } - - void ThenTheAtmShouldNotDispenseAnyMoney() - { - Assert.AreEqual(0, _atm.DispenseValue); - } - - void AndTheAtmShouldSayThereAreInsufficientFunds() - { - Assert.AreEqual(DisplayMessage.InsufficientFunds, _atm.Message); - } - - void AndTheAccountBalanceShouldBe10() - { - Assert.AreEqual(10, _card.AccountBalance); - } - - void AndTheCardShouldBeReturned() - { - Assert.IsFalse(_atm.CardIsRetained); - } - - [TestMethod] - public void Execute() - { - this.BDDfy(); - } - } - } - -This scenario is a bit more involved. Let's run the test and see the reports: - -![ExecutableAttribute console report](/img/BDDfy/exec-attr-console.png) - -*Figure 7. AccountHasInsufficientFund console report* - -![ExecutableAttribute console report](/img/BDDfy/exec-attr-html.png) - -*Figure 8. AccountHasInsufficientFund HTML report* - -When reflecting over your test class, BDDfy looks for a custom attribute called `ExecutableAttribute` on the methods and considers the method decorated with this attribute as a step. You can use attributes either when your method name does not comply with the conventions or when you want to provide a step text that reflection would not be able to create for you. - -To make it easier to use, `ExecutableAttribute` has a few subtypes that you can use. In this scenario, I used `GivenAttribute`, `WhenAttribute` and `AndThenAttribute` attributes because I wanted to show '$' in the step text that would not be possible using method name reflection. Other available attributes are `AndGivenAttribute`, `AndWhenAttribute` and `ThenAttribute`. If you think some other `ExecutableAttribute` could really help you, then you can very easily implement one. - -While we are talking about attributes, there is also an attribute called `IgnoreStepAttribute` that you can apply on a method you want BDDfy to ignore as a step. This is useful when you have a method whose name complies with naming conventions BDDfy uses; but is not really a step. - -As you may have noticed, we have not still implemented any story. BDDfy is capable of executing standalone scenarios and generating report from them which I think is quite useful for teams that do not do Agile/BDD but are interested in a better testing experience and reporting. In this example, we have a story though. So let's code it: - - using TestStack.BDDfy.Core; - using Microsoft.VisualStudio.TestTools.UnitTesting; - - namespace BDDfy.Samples.Atm - { - [TestClass] - [Story( - AsA = "As an Account Holder", - IWant = "I want to withdraw cash from an ATM", - SoThat = "So that I can get money when the bank is closed")] - public class AccountHolderWithdrawsCash - { - [TestMethod] - public void AccountHasInsufficientFund() - { - new AccountHasInsufficientFund().BDDfy(); - } - - [TestMethod] - public void CardHasBeenDisabled() - { - new CardHasBeenDisabled().BDDfy(); - } - } - } - -Any class decorated with a `StoryAttribute` represents a story. Using `StoryAttribute`, you can also specify the story narrative. To associate the story with its scenarios, you should implement a test method per scenario. - -That is it. Just before we run these tests, we should get rid of the Execute test methods in our scenario classes as we no longer need them. We only had them there because we implemented those as standalone scenarios. Now that our scenarios are part of a story, they should not run standalone. Let's run the tests again: - -![Scenario with story console report](/img/BDDfy/story-console.png) - -*Figure 9. Scenarios moved to story - console report* - -We now have only one test class which includes two test methods; one per scenario. Also note that the story narrative is now appearing on the top of the console report for each scenario. - -![Scenario with story html report](/img/BDDfy/story-html.png) - -*Figure 10. Scenarios moved to story - HTML report* - -In the HTML report, the story narrative appears only once above the story's scenarios. - -Note: In the summary section of the HTML report before we implemented the story, we had two namespaces. After adding the story, the namespace count turned into zero and now we instead have one story. BDDfy only counts namespaces for standalone scenarios. - -If you compare the above reports with the ones generated when we had `Execute` methods in the scenarios, you see that these reports group your scenarios by story instead of namespace which makes the reports more readable. - -###Fluent API -Let's do our last scenario. For this one, I am going to use the Fluent API BDDfy provides: - - using Microsoft.VisualStudio.TestTools.UnitTesting; - - namespace BDDfy.Samples.Atm - { - [TestClass] - public class AccountHasSufficientFund - { - private Card _card; - private Atm _atm; - - public void GivenTheAccountBalanceIs(int balance) - { - _card = new Card(true, balance); - } - - public void AndTheCardIsValid() - { - } - - public void AndTheMachineContainsEnoughMoney() - { - _atm = new Atm(100); - } - - public void WhenTheAccountHolderRequests(int moneyRequest) - { - _atm.RequestMoney(_card, moneyRequest); - } - - public void ThenTheAtmShouldDispense(int dispensedMoney) - { - Assert.AreEqual(dispensedMoney, _atm.DispenseValue); - } - - public void AndTheAccountBalanceShouldBe(int balance) - { - Assert.AreEqual(balance, _card.AccountBalance); - } - - public void AndTheCardShouldBeReturned() - { - Assert.IsFalse(_atm.CardIsRetained); - } - } - } - -This looks very much like the other scenarios with one difference: the naming conventions are not quite right and you think that BDDfy would fail to match some of these methods - specifically those starting with `And` instead of `AndGiven`. If you were to use reflecting scanners, those methods would have been picked up as asserting steps which meant they would run and report in incorrect order! You could very easily customise BDDfy's naming conventions or rename your methods or use `ExecutableAttribute` to make these methods scannable by reflecting scanners; but I wrote the class like this to show how you can use a fluent API to let BDDfy find your methods/steps: - - [TestMethod] - public void AccountHasSufficientfund() - { - new AccountHasSufficientFund() - .Given(s => s.GivenTheAccountBalanceIs(100), "Given the account balance is $100") - .And(s => s.AndTheCardIsValid()) - .And(s => s.AndTheMachineContainsEnoughMoney()) - .When(s => s.WhenTheAccountHolderRequests(20), - "When the account holder requests $20") - .Then(s => s.ThenTheAtmShouldDispense(20), "Then the ATM should dispense $20") - .And(s => s.AndTheAccountBalanceShouldBe(80), - "And the account balance should be $80") - .And(s => s.AndTheCardShouldBeReturned()) - .BDDfy(); - } - -You may write this method in your scenario class if you want to run it as a standalone scenario. I added it to my `AccountHolderWithdrawsCash` story to make it part of my story. - -By default, BDDfy uses two scanners namely `MethodNameStepScanner` and `ExecutableAttributeStepScanner` - which I collectively refer to as reflective scanners . The former scans your scenario class for steps using method name conventions and the latter looks for `ExecutableAttribute` on your methods. There is also a third scanner called `FluentStepScanner` which we used in the above example. You don't have to tell BDDfy which scanner to use: it picks the right scanner according to your code. - -Note: Reflective scanners run in a pipeline which means you can mix and match their usage in your scenario; however, when you use `FluentStepScanner`, BDDfy does not use other scanners which means method names and attributes are ignored for scanning methods. In other words, you are in full control of what steps you want run and in what order. - -For reporter modules, it does not make any difference what scanner you use; so the HTML and console reports are going to look the same regardless of the scanners. - -Using fluent API you can implement your stories/scenarios in an alternative and rather interesting way. Instead of having one class per scenario and a class for your story, you could write one class that represents all your scenarios as well as your story: - - using Microsoft.VisualStudio.TestTools.UnitTesting; - using TestStack.BDDfy; - using TestStack.BDDfy.Core; - using TestStack.BDDfy.Scanners.StepScanners.Fluent; - - namespace BDDfy.Samples.Atm - { - [TestClass] - [Story( - Title = "Account holder withdraws cash", - AsA = "As an Account Holder", - IWant = "I want to withdraw cash from an ATM", - SoThat = "So that I can get money when the bank is closed")] - public class AccountHolderWithdrawsCashFluentScanner - { - private const string GivenTheAccountBalanceIsTitleTemplate = - "Given the account balance is ${0}"; - private const string AndTheMachineContainsEnoughMoneyTitleTemplate = - "And the machine contains enough money"; - private const string WhenTheAccountHolderRequestsTitleTemplate = - "When the account holder requests ${0}"; - private const string AndTheCardShouldBeReturnedTitleTemplate = - "And the card should be returned"; - - private Card _card; - private Atm _atm; - - public void GivenTheAccountBalanceIs(int balance) - { - _card = new Card(true, balance); - } - - public void GivenTheCardIsDisabled() - { - _card = new Card(false, 100); - _atm = new Atm(100); - } - - public void AndTheCardIsValid() - { - } - - public void AndTheMachineContains(int atmBalance) - { - _atm = new Atm(atmBalance); - } - - public void WhenTheAccountHolderRequests(int moneyRequest) - { - _atm.RequestMoney(_card, moneyRequest); - } - - public void TheAtmShouldDispense(int dispensedMoney) - { - Assert.AreEqual(dispensedMoney, _atm.DispenseValue); - } - - public void AndTheAccountBalanceShouldBe(int balance) - { - Assert.AreEqual(balance, _card.AccountBalance); - } - - public void CardIsRetained(bool cardIsRetained) - { - Assert.AreEqual(cardIsRetained, _atm.CardIsRetained); - } - - void AndTheAtmShouldSayThereAreInsufficientFunds() - { - Assert.AreEqual(DisplayMessage.InsufficientFunds, _atm.Message); - } - - void AndTheAtmShouldSayTheCardHasBeenRetained() - { - Assert.AreEqual(DisplayMessage.CardIsRetained, _atm.Message); - } - - [TestMethod] - public void AccountHasInsufficientFund() - { - this.Given(s => s.GivenTheAccountBalanceIs(10), - GivenTheAccountBalanceIsTitleTemplate) - .And(s => s.AndTheCardIsValid()) - .And(s => s.AndTheMachineContains(100), - AndTheMachineContainsEnoughMoneyTitleTemplate) - .When(s => s.WhenTheAccountHolderRequests(20), - WhenTheAccountHolderRequestsTitleTemplate) - .Then(s => s.TheAtmShouldDispense(0), "Then the ATM should not dispense") - .And(s => s.AndTheAtmShouldSayThereAreInsufficientFunds()) - .And(s => s.AndTheAccountBalanceShouldBe(10)) - .And(s => s.CardIsRetained(false), - AndTheCardShouldBeReturnedTitleTemplate) - .BDDfy(); - } - - [TestMethod] - public void AccountHasSufficientFund() - { - this.Given(s => s.GivenTheAccountBalanceIs(100), - GivenTheAccountBalanceIsTitleTemplate) - .And(s => s.AndTheCardIsValid()) - .And(s => s.AndTheMachineContains(100), - AndTheMachineContainsEnoughMoneyTitleTemplate) - .When(s => s.WhenTheAccountHolderRequests(20), - WhenTheAccountHolderRequestsTitleTemplate) - .Then(s => s.TheAtmShouldDispense(20), "Then the ATM should dispense $20") - .And(s => s.AndTheAccountBalanceShouldBe(80), - "And the account balance should be $80") - .And(s => s.CardIsRetained(false), - AndTheCardShouldBeReturnedTitleTemplate) - .BDDfy(); - } - - [TestMethod] - public void CardHasBeenDisabled() - { - this.Given(s => s.GivenTheCardIsDisabled()) - .When(s => s.WhenTheAccountHolderRequests(20)) - .Then(s => s.CardIsRetained(true), "Then the ATM should retain the card") - .And(s => s.AndTheAtmShouldSayTheCardHasBeenRetained()) - .BDDfy(); - } - } - } - -This way, you will not need a separate story class or one class per scenario - everything is mixed into one class. Running tests in this class generates the very same console and HTML reports. - -This style of writing stories and scenarios helps you be a bit DRYer; but one could argue it violates [SRP](http://en.wikipedia.org/wiki/Single_responsibility_principle). It is important to note that you could achieve [DRY](http://en.wikipedia.org/wiki/Don't_repeat_yourself)ness without using fluent API. In order to do that, you would need to use inheritance or composition to compose your scenario class from classes that would hold the common behaviors. For example, if you put your 'Given' and 'When' steps inside a base class and your 'Then' steps inside a subclass, BDDfy will scan all these steps into your scenario. That would not give you as much freedom as the fluent API though. - -###Titles -By default, BDDfy uses the name of the story class for the story title as we saw in the first few samples. You can override this behavior by passing the title into the Story attribute as I have done in the above example. I named my class `AccountHolderWithdrawsCashFluentScanner` to differentiate it from the story class in the other implementation; but I do not want the story title to end with 'fluent scanner'. So I provided the story with a title I will be happy to see in the reports: - - [Story( - Title = "Account holder withdraws cash", - AsA = "As an Account Holder", - IWant = "I want to withdraw cash from an ATM", - SoThat = "So that I can get money when the bank is closed")] - public class AccountHolderWithdrawsCashFluentScanner - -For scenario titles, BDDfy uses the class name; for example in the first scenario, BDDfy extracted the scenario text 'Card has been disabled' from the class name 'CardHasBeenDisabled'. In the above example, because all your scenarios are fetched from the same class, one would expect BDDfy to give them all the same title! That is not the case though. In this case, BDDfy detects that you are using fluent API and uses the test method's name to generate the scenario title. For example, the `CardHasBeenDisabled` method results into 'Card has been disabled'. That said, if you want to have full control over scenario title, you may pass the title to BDDfy method; e.g. - - [TestMethod] - public void CardHasBeenDisabled() - { - this.Given(s => s.GivenTheCardIsDisabled()) - .When(s => s.WhenTheAccountHolderRequests(20)) - .Then(s => s.CardIsRetained(true), "Then the ATM should retain the card") - .And(s => s.AndTheAtmShouldSayTheCardHasBeenRetained()) - .BDDfy("Card has been disabled and account holder requests $20"); - } - -BDDfy uses step method names for the method title and it is also capable of injecting the input arguments in the title. In the above example, `Given(s => s.GivenTheCardIsDisabled())` results into 'Given the card is disabled' and `When(s => s.WhenTheAccountHolderRequests(20))` results in 'When the account holder requests 20'; but sometimes that is not good enough (e.g., the account holder does not request 20 - s/he requests 20 dollars). In cases like this, if you are using the fluent API, you can pass in the desired title into the step indicator methods; e.g. - -`And(s => s.CardIsRetained(false), "And the card should be returned")` - -The string that you pass into these methods could also have placeholders for input arguments. This way, you can reuse a string template across several scenarios as I did above. I declared a const on the class level: - -`private const string GivenTheAccountBalanceIsTitleTemplate = "Given the account balance is ${0}";` - -...and then I used it in the step indicator methods like: - -`.Given(s => s.GivenTheAccountBalanceIs(10), GivenTheAccountBalanceIsTitleTemplate)` - -...which resulted in the step title: 'Given the account balance is $10'. It is worth mentioning that BDDfy uses the template in a string.Format() method to generate the title; so you may use as many placeholders and wherever in the title as you like as long as they match the method inputs. - -As mentioned before, when using reflecting scanners you may use `ExecutableAttribute` or a subtype of it to provide custom step texts. The string provided to these attributes also accepts placeholders that are filled by method input arguments. - -Reflective and fluent APIs offer similar functionalities (but some through different means). Below, you may find a quick comparison: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionalityReflecting ScannersFluent Scanner
Story title from story class name YesYes
Story title from Title in StoryAttributeYesYes
Scenario title from scenario class nameYesNo
Scenario title from test method nameNoYes
Custom scenario title passed in BDDfy methodYesYes
Implementing story and scenarios in one classNoYes
Finding step methods using naming conventionYesNo
Finding step methods using attributesYesNo
Finding step methods using lambda expressionNoYes
Running step methods with input argumentsYes - using RunStepWithArgsAttributeYes - using lambda expression
Step title using step method nameYesYes
Using input arguments in the step titleYesYes
Custom step titleYes - using attributesYes - passing into step indicator methods
Using the same method for several stepsYes - using RunStepWithArgsAttributeYes
Ignoring a method as stepYes - using IgnoreAttributeN/A - Do not indicate the method
Dispose methodYes - Implement a method starting with 'TearDown'Yes - Use TearDownWith step indicator
Using inherited step methodsYesYes
- - -You may think that these two APIs are significantly different and that a huge amount of effort has been put to implement both models; but the ONLY difference between these two models is in their step scanners which are not even part of the core. BDDfy is very extensible and the core barely has any logic in it. It instead delegates all its responsibilities to its extensions, one of which is step scanner implementing `IStepScanner`. The same applies to scenario scanner implemening `IScenarioScanner`, and story scanner implementing `IScanner`, report generators, test runner and exception handler etc. All these interfaces contain only one method which makes it rather straightforward to implement a new extension. Step scanners are a very small part of this framework, and if you think you could benefit from a different scanner you could very simply implement it. - -The sample we worked through in this article is one of the BDDfy samples. There are a few more samples that are implemented in different ways and use some other BDDfy features I did not explain here and I think are definitely worth looking. Samples are available on TestStack.BDDfy.Samples NuGet package. The samples are all implemented using NUnit; but as shown in this article you can use MSTest or any other testing framework. diff --git a/images/bg_hr.png b/images/bg_hr.png new file mode 100644 index 00000000..7973bd69 Binary files /dev/null and b/images/bg_hr.png differ diff --git a/images/blacktocat.png b/images/blacktocat.png new file mode 100644 index 00000000..6e264fe5 Binary files /dev/null and b/images/blacktocat.png differ diff --git a/images/icon_download.png b/images/icon_download.png new file mode 100644 index 00000000..a2a287f6 Binary files /dev/null and b/images/icon_download.png differ diff --git a/images/sprite_download.png b/images/sprite_download.png new file mode 100644 index 00000000..f2babd57 Binary files /dev/null and b/images/sprite_download.png differ diff --git a/index.html b/index.html new file mode 100644 index 00000000..71579258 --- /dev/null +++ b/index.html @@ -0,0 +1,46 @@ + + + + + + +Redirecting to BDDfy portal + + + + + + + + + + +
+
+ View on GitHub + +

BDDfy

+

BDDfy is the simplest BDD framework EVER!

+ +
+ Download this project as a .zip file + Download this project as a tar.gz file +
+
+
+ + +
+
+This page has moved. You will be automatically redirected to its new location in 10 seconds. +If you aren't forwarded to the new page, click here. +
+
+ + + + diff --git a/javascripts/main.js b/javascripts/main.js new file mode 100644 index 00000000..d8135d37 --- /dev/null +++ b/javascripts/main.js @@ -0,0 +1 @@ +console.log('This would be the main JS file.'); diff --git a/license.txt b/license.txt deleted file mode 100644 index ae5f0482..00000000 --- a/license.txt +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2011-2013 TestStack.BDDfy Contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file diff --git a/logo.png b/logo.png deleted file mode 100644 index ac87c2e5..00000000 Binary files a/logo.png and /dev/null differ diff --git a/params.json b/params.json new file mode 100644 index 00000000..9c5c5b71 --- /dev/null +++ b/params.json @@ -0,0 +1 @@ +{"tagline":"BDDfy is the simplest BDD framework EVER! ","note":"Don't delete this file! It's used internally to help with page regeneration.","google":"","body":"## What's with the name?\r\nThe framework is called BDDfy because it BDDfies (as in turns into BDD) your otherwise traditional unit tests. Oh and BTW it is pronounced B D Defy. With BDDfy it is very simple to turn your AAA tests into a BDD test/behavior. BDDfy can work with any and all testing frameworks. In fact, it works even if you are not using any testing framework.\r\n\r\nThe framework is explained on Mehdi Khalili's blog series in full details [here] (http://www.mehdi-khalili.com/bddify-in-action/introduction).\r\n\r\n## How to get going\r\n1. Install NuGet if you have not already.\r\n2. Go to 'Tools', 'Library Package Manager', and click 'Package Manager Console'.\r\n3. In the console, type 'Install-Package TestStack.BDDfy' and enter. \r\n\r\nThis adds the BDDfy assembly to your test project. \r\n\r\nIf this is the first time you are using BDDfy you may want to check out some of the samples on NuGet. Just search NuGet for BDDfy and you will see a list of BDDfy samples. You may install one or more samples to see how the framework works. Each sample installs required packages (including BDDfy and NUnit).\r\n\r\n## Highlights\r\n* BDDfy can run with any testing framework. It does not force you to use any particular framework. Actually BDDfy does not force you to use a testing framework at all. You can just apply it on POCO classes even in a console app if that is what you need!\r\n* BDDfy does not need a separate test runner. You can use your runner of choice. For example, if you like NUnit, then you may write your BDDfy tests using NUnit and run them using NUnit console or GUI runner, Resharper or TD.Net and regardless of the runner, you will get the same result. This means it integrates with the tools you know and love instead of adding yet another one on the top of them.\r\n* BDDfy can run standalone scenarios. Although BDDfy supports stories, you do not necessarily have to have or make up a story to use BDDfy. This is useful for developers who work in non-Agile environments but would like to get some decent testing experience.\r\n* You can use underscored or pascal or camel cased method names for your steps.\r\n* You do not have to explain your scenarios or stories or steps in string: BDDfy infers them based on conventions but you can override the conventions if you need full control over what gets printed into console and HTML reports. Conventions galore in BDDfy and pretty much everything has a convention; but it is also very easy to override these conventions.\r\n* BDDfy is very extensible. In fact, BDDfy core barely has any logic in it. It delegates all its responsibilities to its extensions.\r\n* BDDfy learning curve is rather flat. Not only that but it makes learning BDD effortless.\r\n\r\n##Quick start\r\nNow that you have installed BDDfy, write your first test (this test is borrowed from ATM sample that you can install using nuget package TestStack.BDDfy.Samples):\r\n\r\n\t[Story(\r\n AsA = \"As an Account Holder\",\r\n IWant = \"I want to withdraw cash from an ATM\",\r\n SoThat = \"So that I can get money when the bank is closed\")]\r\n\tpublic class AccountHasInsufficientFund\r\n\t{\r\n\t private Card _card;\r\n\t private Atm _atm;\r\n\t\r\n\t // You can override step text using executable attributes\r\n\t [Given(StepText = \"Given the account balance is $10\")]\r\n\t void GivenAccountHasEnoughBalance()\r\n\t {\r\n\t _card = new Card(true, 10);\r\n\t }\r\n\t\r\n\t void AndGivenTheCardIsValid()\r\n\t {\r\n\t }\r\n\t\r\n\t void AndGivenTheMachineContainsEnoughMoney()\r\n\t {\r\n\t _atm = new Atm(100);\r\n\t }\r\n\t\r\n\t void WhenTheAccountHolderRequests20()\r\n\t {\r\n\t _atm.RequestMoney(_card, 20);\r\n\t }\r\n\t\r\n\t void ThenTheAtmShouldNotDispenseAnyMoney()\r\n\t {\r\n\t Assert.AreEqual(0, _atm.DispenseValue);\r\n\t }\r\n\t\r\n\t void AndTheAtmShouldSayThereAreInsufficientFunds()\r\n\t {\r\n\t Assert.AreEqual(DisplayMessage.InsufficientFunds, _atm.Message);\r\n\t }\r\n\t\r\n\t void AndTheCardShouldBeReturned()\r\n\t {\r\n\t Assert.IsFalse(_atm.CardIsRetained);\r\n\t }\r\n\t\r\n\t [Test]\r\n\t public void Execute()\r\n\t {\r\n\t this.BDDfy();\r\n\t }\r\n\t}\r\n\r\n\r\nAnd this gives you a report like:\r\n\r\n\tStory: Account holder withdraws cash\r\n \tAs an Account Holder\r\n \tI want to withdraw cash from an ATM\r\n \tSo that I can get money when the bank is closed\r\n\r\n\tScenario: Account has insufficient fund\r\n \tGiven the account balance is $10\r\n \t\tAnd the card is valid\r\n \tWhen the account holder requests $20\r\n \tThen the atm should not dispense any money\r\n \t\tAnd the atm should say there are insufficient funds\r\n \t\tAnd the card should be returned\r\n\r\nThis is just the console report. Have a look at your output folder and you should see a nice html report too.\r\n\r\nIf you want more control you can also use BDDfy's Fluent API. Here is another example done using the Fluent API:\r\n\r\n\r\n\t[Test]\r\n\tpublic void CardHasBeenDisabled()\r\n\t{\r\n\t this.Given(s => s.GivenTheCardIsDisabled())\r\n\t .When(s => s.WhenTheAccountHolderRequests(20))\r\n\t .Then(s => s.CardIsRetained(true), \"Then the ATM should retain the card\")\r\n\t .And(s => s.AndTheAtmShouldSayTheCardHasBeenRetained())\r\n\t .BDDfy(htmlReportName: \"ATM\");\r\n\t}\r\n\r\nwhich gives you a report like:\r\n\r\n\tScenario: Card has been disabled\r\n \tGiven the card is disabled\r\n \tWhen the account holder requests 20\r\n \tThen the ATM should retain the card\r\n \t\tAnd the atm should say the card has been retained\r\n\r\n\r\n##How does BDDfy work?\r\nBDDfy uses quite a few conventions to make it frictionless to use. For your convenience, I will try to provide a quick tutorial below:\r\n\r\n###Finding steps\r\nBDDfy scans your BDDfyed classes for steps. Currently it has three ways of finding a step: \r\n\r\n* Using attributes \r\n* Using method name conventions \r\n* And using fluent API.\r\n\r\nBDDfy runs your steps in the following order: SetupState, ConsecutiveSetupState, Transition, ConsecutiveTransition, Assertion, ConsecutiveAssertion and TearDown. Some of these steps are reported in the console and html reports and some of them are not. Please read below for further information.\r\n\r\n###Attributes\r\nBDDfy looks for a custom attribute called ExecutableAttribute on your method. To make it easier to use, ExecutableAttribute has a few subclasses that you can use: you may apply Given, AndGiven, When, AndWhen, Then, and AndThen attributes on any method you want to make available to BDDfy.\r\n\r\n###Method name convention\r\nBDDfy uses some conventions to find methods that should be turned into steps. Here is the current conventions. The method name:\r\n\r\n* ending with \"Context\" is considered as a setup method (not reported).\r\n* \"Setup\" is considered as as setup method (not reported). \r\n* starting with \"Given\" is considered as a setup method (reported). \r\n* starting with \"AndGiven\" is considered as a setup method that runs after Context, Setup and Given steps reported).\r\n* starting with \"When\" is considered as a transition method (reported). \r\n* starting with \"AndWhen\" is considered as a transition method that runs after When steps (reported).\r\n* starting with \"Then\" is considered as an asserting method (reported).\r\n* starting with \"And\" is considered as an asserting method (reported).\r\n* starting with \"TearDown\" is considered as a finally method which is run after all the other steps (not reported).\r\n\r\nAs you see in the above example you can mix and match the executable attributes and method name conventions to acheive great flexibility and power.\r\n\r\n###Fluent API\r\nFluent API gives you the absolute power over step selection and their titles. When you use Fluent API for a test, the attributes and method name conventions are ignored for that test. \r\n\r\nPlease note that you can have some tests using fluent API and some using a combination of attributes and method name conventions. Each .BDDfy() test works in isolation of others.\r\n\r\n###Other conventions\r\nBDDfy prefers convention over configuration; but it also allows you to configure pretty much all the conventions. \r\n\r\n## Authors and Contributors\r\nMehdi Khalili (@MehdiK), Michael Whelan (@mwhelan)","name":"BDDfy"} \ No newline at end of file diff --git a/readme.md b/readme.md deleted file mode 100644 index 10ad5c22..00000000 --- a/readme.md +++ /dev/null @@ -1,132 +0,0 @@ -BDDfy is the simplest BDD framework to use, customize and extend! - -A few quick facts about BDDfy: - - It can run with any testing framework. Actually you don't have to use a testing framework at all. You can just apply it on your POCO (test) classes! - - It does not need a separate test runner. You can use your runner of choice. For example, you can write your BDDfy tests using NUnit and run them using NUnit console or GUI runner, Resharper or TD.Net and regardless of the runner, you will get the same result. - - It can run standalone scenarios. In other words, although BDDfy supports stories, you do not necessarily have to have or make up a story to use it. This is useful for developers who work in non-Agile environments but would like to get some decent testing experience. - - You can use underscored or pascal or camel cased method names for your steps. - - You do not have to explain your scenarios or stories or steps in string, but you can if you need full control over what gets printed into console and HTML reports. - - BDDfy is very extensible: the core barely has any logic in it and delegates all its responsibilities to the extensions all of which are configurable; e.g. if you don't like the reports it generates, you can write your custom reporter in a few lines of code. - -## Usage - -[![Join the chat at https://gitter.im/TestStack/TestStack.BDDfy](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/TestStack/TestStack.BDDfy?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -To use BDDfy install TestStack.BDDfy nuget package: `Install-Package TestStack.BDDfy` - -This adds BDDfy assembly and its dependencies to your test project. If this is the first time you are using BDDfy you may want to check out the samples on NuGet. Just run `Install-Package TestStack.BDDfy.Samples` and it will load two fully working samples to your project. - -Now that you have installed BDDfy, write your first test (this test is borrowed from ATM sample that you can install using nuget package TestStack.BDDfy.Samples): - -````csharp - [Story( - AsA = "As an Account Holder", - IWant = "I want to withdraw cash from an ATM", - SoThat = "So that I can get money when the bank is closed")] - public class AccountHasInsufficientFund - { - private Card _card; - private Atm _atm; - - // You can override step text using executable attributes - [Given(StepText = "Given the account balance is $10")] - void GivenAccountHasEnoughBalance() - { - _card = new Card(true, 10); - } - - void AndGivenTheCardIsValid() - { - } - - void AndGivenTheMachineContainsEnoughMoney() - { - _atm = new Atm(100); - } - - void WhenTheAccountHolderRequests20() - { - _atm.RequestMoney(_card, 20); - } - - void ThenTheAtmShouldNotDispenseAnyMoney() - { - Assert.AreEqual(0, _atm.DispenseValue); - } - - void AndTheAtmShouldSayThereAreInsufficientFunds() - { - Assert.AreEqual(DisplayMessage.InsufficientFunds, _atm.Message); - } - - void AndTheCardShouldBeReturned() - { - Assert.IsFalse(_atm.CardIsRetained); - } - - [Fact] - public void Execute() - { - this.BDDfy(); - } - } -```` - -And this gives you a report like: - - Story: Account holder withdraws cash - As an Account Holder - I want to withdraw cash from an ATM - So that I can get money when the bank is closed - - Scenario: Account has insufficient fund - Given the account balance is $10 - And the card is valid - When the account holder requests $20 - Then the atm should not dispense any money - And the atm should say there are insufficient funds - And the card should be returned - -This is just the console report. Have a look at your output folder and you should see a nice html report too. - -If you want more control you can also use BDDfy's Fluent API. Here is another example done using the Fluent API: - -````csharp - [Fact] - public void CardHasBeenDisabled() - { - this.Given(s => s.GivenTheCardIsDisabled()) - .When(s => s.WhenTheAccountHolderRequests(20)) - .Then(s => s.CardIsRetained(true), "Then the ATM should retain the card") - .And(s => s.AndTheAtmShouldSayTheCardHasBeenRetained()) - .BDDfy(htmlReportName: "ATM"); - } -```` - -which gives you a report like: - - Scenario: Card has been disabled - Given the card is disabled - When the account holder requests 20 - Then the ATM should retain the card - And the atm should say the card has been retained - -## IDE annotations - -This repository contains a small set of in-repo code-analysis annotations (see `src/TestStack.BDDfy/Properties/Annotations.cs`). - -Notably, the attribute classes used for step discovery (for example `ExecutableAttribute` and the GWT attribute variants) are marked with a local `MeansImplicitUse` attribute. That makes methods decorated with `[Executable]` (or `[Given]`, `[When]`, `[Then]`, etc.) be treated as "used implicitly" by IDEs such as ReSharper or Rider. The effect: you won't see "unused" inspections on step methods even though they're invoked via reflection at runtime. - -If you prefer to use the official `JetBrains.Annotations` NuGet package instead of the in-repo annotations, you can replace the local attributes and add the package as a development-only dependency (use `PrivateAssets="all"` on the package reference so it doesn't become transitive). - - -This is only the tip of iceberg. Absolutely everything you do with BDDfy is extensible and customizable. -You might see full documentation of BDDfy on the [TestStack documentation website](http://bddfy.teststack.net/). -Oh and while you are there don't forget to checkout other cool projects from [TestStack](http://www.teststack.net/). - -## Authors -* [Mehdi Khalili](https://github.com/MehdiK) -* [Michael Whelan](https://github.com/mwhelan) -* [Jake Ginnivan](https://github.com/JakeGinnivan) - -## License -BDDfy is released under the MIT License. See the bundled license.txt file for details. \ No newline at end of file diff --git a/src/.editorconfig b/src/.editorconfig deleted file mode 100644 index dd2b5504..00000000 --- a/src/.editorconfig +++ /dev/null @@ -1,4 +0,0 @@ -[*.cs] - -# Default severity for analyzer diagnostics with category 'Style' -dotnet_analyzer_diagnostic.category-Style.severity = none diff --git a/src/Directory.build.props b/src/Directory.build.props deleted file mode 100644 index 19bc63e5..00000000 --- a/src/Directory.build.props +++ /dev/null @@ -1,5 +0,0 @@ - - - net8.0 - - \ No newline at end of file diff --git a/src/Samples/TestStack.BDDfy.Samples/AssemblySetupFixture.cs b/src/Samples/TestStack.BDDfy.Samples/AssemblySetupFixture.cs deleted file mode 100644 index 8d2aa259..00000000 --- a/src/Samples/TestStack.BDDfy.Samples/AssemblySetupFixture.cs +++ /dev/null @@ -1,147 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Threading; -using System.Threading.Tasks; -using TestStack.BDDfy.Configuration; -using TestStack.BDDfy.Reporters.Html; -using TestStack.BDDfy.Samples; -using TestStack.BDDfy.Samples.Atm; -using Xunit.Abstractions; -using Xunit.Sdk; - -// The custom test framework enables the support -[assembly: Xunit.TestFramework("TestStack.BDDfy.Samples.XunitTestFrameworkWithAssemblyFixture", "TestStack.BDDfy.Samples")] - -// Add one of these for every fixture classes for the assembly. -// Just like other fixtures, you can implement IDisposable and it'll -// get cleaned up at the end of the test run. -[assembly: AssemblyFixture(typeof(AssemblySetupFixture))] - -namespace TestStack.BDDfy.Samples -{ - public class AssemblySetupFixture - { - public AssemblySetupFixture() - { - Configurator.Processors.Add(() => new CustomTextReporter()); - Configurator.BatchProcessors.MarkDownReport.Enable(); - Configurator.BatchProcessors.DiagnosticsReport.Enable(); - Configurator.BatchProcessors.Add(new HtmlReporter(new AtmHtmlReportConfig(), new MetroReportBuilder())); - } - } - - [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] - public class AssemblyFixtureAttribute(Type fixtureType): Attribute - { - public Type FixtureType { get; private set; } = fixtureType; - } - - public class XunitTestFrameworkWithAssemblyFixture(IMessageSink messageSink): XunitTestFramework(messageSink) - { - protected override ITestFrameworkExecutor CreateExecutor(AssemblyName assemblyName) - => new XunitTestFrameworkExecutorWithAssemblyFixture(assemblyName, SourceInformationProvider, DiagnosticMessageSink); - } - - public class XunitTestFrameworkExecutorWithAssemblyFixture(AssemblyName assemblyName, - ISourceInformationProvider sourceInformationProvider, IMessageSink diagnosticMessageSink): - XunitTestFrameworkExecutor(assemblyName, sourceInformationProvider, diagnosticMessageSink) - { - protected override async void RunTestCases(IEnumerable testCases, - IMessageSink executionMessageSink, ITestFrameworkExecutionOptions executionOptions) - { - using var assemblyRunner = new XunitTestAssemblyRunnerWithAssemblyFixture(TestAssembly, testCases, - DiagnosticMessageSink, executionMessageSink, executionOptions); - await assemblyRunner.RunAsync(); - } - } - - public class XunitTestAssemblyRunnerWithAssemblyFixture(ITestAssembly testAssembly, - IEnumerable testCases, - IMessageSink diagnosticMessageSink, - IMessageSink executionMessageSink, - ITestFrameworkExecutionOptions executionOptions): - XunitTestAssemblyRunner(testAssembly, testCases, diagnosticMessageSink, executionMessageSink, executionOptions) - { - readonly Dictionary assemblyFixtureMappings = new(); - - protected override async Task AfterTestAssemblyStartingAsync() - { - // Let everything initialize - await base.AfterTestAssemblyStartingAsync(); - - // Go find all the AssemblyFixtureAttributes adorned on the test assembly - Aggregator.Run(() => - { - var fixturesAttrs = ((IReflectionAssemblyInfo)TestAssembly.Assembly).Assembly - .GetCustomAttributes(typeof(AssemblyFixtureAttribute)) - .Cast() - .ToList(); - - // Instantiate all the fixtures - foreach (var fixtureAttr in fixturesAttrs) - assemblyFixtureMappings[fixtureAttr.FixtureType] = Activator.CreateInstance(fixtureAttr.FixtureType); - }); - } - - protected override Task BeforeTestAssemblyFinishedAsync() - { - // Make sure we clean up everybody who is disposable, and use Aggregator.Run to isolate Dispose failures - foreach (var disposable in assemblyFixtureMappings.Values.OfType()) - Aggregator.Run(disposable.Dispose); - - return base.BeforeTestAssemblyFinishedAsync(); - } - - protected override Task RunTestCollectionAsync(IMessageBus messageBus, - ITestCollection testCollection, - IEnumerable testCases, - CancellationTokenSource cancellationTokenSource) - => new XunitTestCollectionRunnerWithAssemblyFixture( - assemblyFixtureMappings, - testCollection, - testCases, - DiagnosticMessageSink, - messageBus, - TestCaseOrderer, - new ExceptionAggregator(Aggregator), - cancellationTokenSource).RunAsync(); - } - - public class XunitTestCollectionRunnerWithAssemblyFixture(Dictionary assemblyFixtureMappings, - ITestCollection testCollection, - IEnumerable testCases, - IMessageSink diagnosticMessageSink, - IMessageBus messageBus, - ITestCaseOrderer testCaseOrderer, - ExceptionAggregator aggregator, - CancellationTokenSource cancellationTokenSource): - XunitTestCollectionRunner(testCollection, testCases, diagnosticMessageSink, messageBus, testCaseOrderer, aggregator, cancellationTokenSource) - { - readonly Dictionary assemblyFixtureMappings = assemblyFixtureMappings; - readonly IMessageSink diagnosticMessageSink = diagnosticMessageSink; - - protected override Task RunTestClassAsync(ITestClass testClass, IReflectionTypeInfo @class, IEnumerable testCases) - { - // Don't want to use .Concat + .ToDictionary because of the possibility of overriding types, - // so instead we'll just let collection fixtures override assembly fixtures. - var combinedFixtures = new Dictionary(assemblyFixtureMappings); - foreach (var kvp in CollectionFixtureMappings) - combinedFixtures[kvp.Key] = kvp.Value; - - // We've done everything we need, so let the built-in types do the rest of the heavy lifting - return new XunitTestClassRunner( - testClass, - @class, - testCases, - diagnosticMessageSink, - MessageBus, - TestCaseOrderer, - new ExceptionAggregator(Aggregator), - CancellationTokenSource, - combinedFixtures).RunAsync(); - } - } - -} \ No newline at end of file diff --git a/src/Samples/TestStack.BDDfy.Samples/Atm/AccountHasInsufficientFund.cs b/src/Samples/TestStack.BDDfy.Samples/Atm/AccountHasInsufficientFund.cs deleted file mode 100644 index e9e2a205..00000000 --- a/src/Samples/TestStack.BDDfy.Samples/Atm/AccountHasInsufficientFund.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Samples.Atm -{ - public class AccountHasInsufficientFund - { - private Card _card; - private Atm _atm; - - // You can override step text using executable attributes - [Given("Given the Account Balance is $10")] - void GivenTheAccountBalanceIs10() - { - _card = new Card(true, 10); - } - - void And_given_the_Card_is_valid() - { - } - - void AndGivenTheMachineContainsEnoughMoney() - { - _atm = new Atm(100); - } - - [When("When the Account Holder requests $20")] - void WhenTheAccountHolderRequests20() - { - _atm.RequestMoney(_card, 20); - } - - void Then_the_ATM_should_not_dispense_any_Money() - { - _atm.DispenseValue.ShouldBe(0); - } - - void And_the_ATM_should_say_there_are_Insufficient_Funds() - { - _atm.Message.ShouldBe(DisplayMessage.InsufficientFunds); - } - - [AndThen("And the Account Balance should be $20")] - void AndTheAccountBalanceShouldBe20() - { - _card.AccountBalance.ShouldBe(10); - } - - void And_the_Card_should_be_returned() - { - _atm.CardIsRetained.ShouldBe(false); - } - - [Fact] - public void Verify() - { - this.BDDfy(); - } - } -} \ No newline at end of file diff --git a/src/Samples/TestStack.BDDfy.Samples/Atm/AccountHolderWithdrawsCash.cs b/src/Samples/TestStack.BDDfy.Samples/Atm/AccountHolderWithdrawsCash.cs deleted file mode 100644 index a31fb495..00000000 --- a/src/Samples/TestStack.BDDfy.Samples/Atm/AccountHolderWithdrawsCash.cs +++ /dev/null @@ -1,90 +0,0 @@ -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Samples.Atm -{ - [Story( - AsA = "As an Account Holder", - IWant = "I want to withdraw cash from an ATM", - SoThat = "So that I can get money when the bank is closed", - ImageUri = "https://upload.wikimedia.org/wikipedia/commons/d/d3/49024-SOS-ATM.JPG", - StoryUri = "http://google.com")] - public class AccountHolderWithdrawsCash - { - private const string GivenTheAccountBalanceIsTitleTemplate = "Given the account balance is ${0}"; - private const string AndTheMachineContainsEnoughMoneyTitleTemplate = "And the machine contains enough money"; - private const string WhenTheAccountHolderRequestsTitleTemplate = "When the account holder requests ${0}"; - private const string AndTheCardShouldBeReturnedTitleTemplate = "And the card should be returned"; - - private Card _card; - private Atm _atm; - - internal void Given_the_Account_Balance_is(int balance) - { - _card = new Card(true, balance); - } - - internal void Given_the_Card_is_disabled() - { - _card = new Card(false, 100); - _atm = new Atm(100); - } - - internal void And_the_Card_is_valid() - { - } - - internal void And_the_machine_contains(int atmBalance) - { - _atm = new Atm(atmBalance); - } - - internal void When_the_Account_Holder_requests(int moneyRequest) - { - _atm.RequestMoney(_card, moneyRequest); - } - - internal void The_ATM_should_dispense(int dispensedMoney) - { - _atm.DispenseValue.ShouldBe(dispensedMoney); - } - - internal void And_the_Account_Balance_should_be(int balance) - { - _card.AccountBalance.ShouldBe(balance); - } - - internal void Then_Card_is_retained(bool cardIsRetained) - { - _atm.CardIsRetained.ShouldBe(cardIsRetained); - } - - internal void And_the_ATM_should_say_the_Card_has_been_retained() - { - _atm.Message.ShouldBe(DisplayMessage.CardIsRetained); - } - - [Fact] - public void AccountHasSufficientFund() - { - this.Given(s => s.Given_the_Account_Balance_is(100), GivenTheAccountBalanceIsTitleTemplate) - .And(s => s.And_the_Card_is_valid()) - .And(s => s.And_the_machine_contains(100), AndTheMachineContainsEnoughMoneyTitleTemplate) - .When(s => s.When_the_Account_Holder_requests(20), WhenTheAccountHolderRequestsTitleTemplate) - .Then(s => s.The_ATM_should_dispense(20), "Then the ATM should dispense $20") - .And(s => s.And_the_Account_Balance_should_be(80), "And the account balance should be $80") - .And(s => s.Then_Card_is_retained(false), AndTheCardShouldBeReturnedTitleTemplate) - .BDDfy(); - } - - [Fact] - public void CardHasBeenDisabled() - { - this.Given(s => s.Given_the_Card_is_disabled()) - .When(s => s.When_the_Account_Holder_requests(20)) - .Then(s => s.Then_Card_is_retained(true), false) // in here I am telling the fluent API that I do not want it to include the input arguments in the step title - .And(s => s.And_the_ATM_should_say_the_Card_has_been_retained()) - .BDDfy(); - } - } -} \ No newline at end of file diff --git a/src/Samples/TestStack.BDDfy.Samples/Atm/Atm.cs b/src/Samples/TestStack.BDDfy.Samples/Atm/Atm.cs deleted file mode 100644 index ede74525..00000000 --- a/src/Samples/TestStack.BDDfy.Samples/Atm/Atm.cs +++ /dev/null @@ -1,50 +0,0 @@ -namespace TestStack.BDDfy.Samples.Atm -{ - public class Atm(int existingCash) - { - public int ExistingCash { get; private set; } = existingCash; - - public void RequestMoney(Card card, int request) - { - if (!card.Enabled) - { - CardIsRetained = true; - Message = DisplayMessage.CardIsRetained; - return; - } - - if(card.AccountBalance < request) - { - Message = DisplayMessage.InsufficientFunds; - return; - } - - DispenseValue = request; - card.AccountBalance -= request; - } - - public int DispenseValue { get; set; } - - public bool CardIsRetained { get; private set; } - - public DisplayMessage Message { get; private set; } - } - - public class Card(bool enabled, int accountBalance) - { - public int AccountBalance { get; set; } = accountBalance; - private readonly bool _enabled = enabled; - - public bool Enabled - { - get { return _enabled; } - } - } - - public enum DisplayMessage - { - None = 0, - CardIsRetained, - InsufficientFunds - } -} \ No newline at end of file diff --git a/src/Samples/TestStack.BDDfy.Samples/Atm/AtmHtmlReportConfig.cs b/src/Samples/TestStack.BDDfy.Samples/Atm/AtmHtmlReportConfig.cs deleted file mode 100644 index 25f93568..00000000 --- a/src/Samples/TestStack.BDDfy.Samples/Atm/AtmHtmlReportConfig.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System; -using TestStack.BDDfy.Reporters.Html; - -namespace TestStack.BDDfy.Samples.Atm -{ - /// - /// This overrides the default html report setting - /// - public class AtmHtmlReportConfig : DefaultHtmlReportConfiguration - { - public override bool RunsOn(Story story) - { - return story.Namespace.EndsWith("Atm", StringComparison.OrdinalIgnoreCase); - } - - /// - /// Change the output file name - /// - public override string OutputFileName - { - get - { - return "ATM.html"; - } - } - - /// - /// Change the report header to your project - /// - public override string ReportHeader - { - get - { - return "ATM Solutions"; - } - } - - /// - /// Change the report description - /// - public override string ReportDescription - { - get - { - return "A reliable solution for your offline banking needs"; - } - } - - /// - /// For ATM report I want to embed jQuery in the report so people can see it with no internet connectivity - /// - public override bool ResolveJqueryFromCdn - { - get { return false; } - } - } -} \ No newline at end of file diff --git a/src/Samples/TestStack.BDDfy.Samples/BDDfy_Rocks.cs b/src/Samples/TestStack.BDDfy.Samples/BDDfy_Rocks.cs deleted file mode 100644 index ca788f65..00000000 --- a/src/Samples/TestStack.BDDfy.Samples/BDDfy_Rocks.cs +++ /dev/null @@ -1,45 +0,0 @@ -using Xunit; - -namespace TestStack.BDDfy.Samples -{ - [Story( - AsA = "As a .Net programmer", - IWant = "I want to use BDDfy", - SoThat = "So that BDD becomes easy and fun", - ImageUri = "https://upload.wikimedia.org/wikipedia/commons/7/72/DirkvdM_rocks.jpg", - StoryUri = "https://en.wikipedia.org/wiki/Rock_%28geology%29")] - public class BDDfy_Rocks - { - void Given_I_have_not_used_BDDfy_before() - { - } - - void WhenIAmIntroducedToTheFramework() - { - } - - void ThenILikeItAndStartUsingIt() - { - } - - void AndTheQualityAndMaintainabilityOfMyTestSkyrocket() - { - } - - [Fact] - public void BDDfy_with_reflective_API() - { - this.BDDfy(); - } - - [Fact] - public void BDDfy_with_fluent_API() - { - this.Given(_ => Given_I_have_not_used_BDDfy_before()) - .When(_ => WhenIAmIntroducedToTheFramework()) - .Then(_ => ThenILikeItAndStartUsingIt()) - .And(_ => AndTheQualityAndMaintainabilityOfMyTestSkyrocket()) - .BDDfy(); - } - } -} diff --git a/src/Samples/TestStack.BDDfy.Samples/BuyingTrainFareWithExamples.cs b/src/Samples/TestStack.BDDfy.Samples/BuyingTrainFareWithExamples.cs deleted file mode 100644 index 9a0a9c4c..00000000 --- a/src/Samples/TestStack.BDDfy.Samples/BuyingTrainFareWithExamples.cs +++ /dev/null @@ -1,61 +0,0 @@ -using TestStack.BDDfy.Samples.BuyingTrainFares; -using Xunit; - -namespace TestStack.BDDfy.Samples -{ - public class BuyingTrainFareWithExamples - { - #pragma warning disable 649 - // ReSharper disable once InconsistentNaming - private Fare fare; - private BuyerCategory _buyerCategory; - #pragma warning restore 649 - Money Price { get; set; } - - [Fact] - public void SuccessfulRailCardPurchases() - { - this.Given(_ => TheBuyerIsA(_buyerCategory)) - .And(_ => TheBuyerSelectsA(fare)) - .When(_ => TheBuyerPays()) - .Then(_ => ASaleOccursWithAnAmountOf(Price)) - .WithExamples(new ExampleTable( - "Buyer Category", "Fare", "Price") - { - {BuyerCategory.Student, new MonthlyPass(), new Money(76)}, - {BuyerCategory.Senior, new MonthlyPass(), new Money(98)}, - {BuyerCategory.Standard, new MonthlyPass(), new Money(146)}, - {BuyerCategory.Student, new WeeklyPass(), new Money(23)}, - {BuyerCategory.Senior, new WeeklyPass(), new Money(30)}, - {BuyerCategory.Standard, new WeeklyPass(), new Money(44)}, - {BuyerCategory.Student, new DayPass(), new Money(4)}, - {BuyerCategory.Senior, new DayPass(), new Money(5)}, - {BuyerCategory.Standard, new DayPass(), new Money(7)}, - {BuyerCategory.Student, new SingleTicket(), new Money(1.5m)}, - {BuyerCategory.Senior, new SingleTicket(), new Money(2m)}, - {BuyerCategory.Standard, new SingleTicket(), new Money(3m)} - }) - .BDDfy("Successful rail card purchases"); - } - - void TheBuyerIsA(BuyerCategory buyerCategory) - { - - } - - void TheBuyerSelectsA(Fare fare) - { - - } - - void TheBuyerPays() - { - - } - - void ASaleOccursWithAnAmountOf(Money price) - { - - } - } -} \ No newline at end of file diff --git a/src/Samples/TestStack.BDDfy.Samples/BuyingTrainFares/BuyerCategory.cs b/src/Samples/TestStack.BDDfy.Samples/BuyingTrainFares/BuyerCategory.cs deleted file mode 100644 index b78f699c..00000000 --- a/src/Samples/TestStack.BDDfy.Samples/BuyingTrainFares/BuyerCategory.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace TestStack.BDDfy.Samples.BuyingTrainFares -{ - enum BuyerCategory - { - Student, - Senior, - Standard - } -} \ No newline at end of file diff --git a/src/Samples/TestStack.BDDfy.Samples/BuyingTrainFares/DayPass.cs b/src/Samples/TestStack.BDDfy.Samples/BuyingTrainFares/DayPass.cs deleted file mode 100644 index 22f5f5cf..00000000 --- a/src/Samples/TestStack.BDDfy.Samples/BuyingTrainFares/DayPass.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace TestStack.BDDfy.Samples.BuyingTrainFares -{ - class DayPass : Fare - { - public override string ToString() - { - return "Day Pass"; - } - } -} \ No newline at end of file diff --git a/src/Samples/TestStack.BDDfy.Samples/BuyingTrainFares/Fare.cs b/src/Samples/TestStack.BDDfy.Samples/BuyingTrainFares/Fare.cs deleted file mode 100644 index a397dab3..00000000 --- a/src/Samples/TestStack.BDDfy.Samples/BuyingTrainFares/Fare.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace TestStack.BDDfy.Samples.BuyingTrainFares -{ - class Fare - { - - } -} \ No newline at end of file diff --git a/src/Samples/TestStack.BDDfy.Samples/BuyingTrainFares/Money.cs b/src/Samples/TestStack.BDDfy.Samples/BuyingTrainFares/Money.cs deleted file mode 100644 index b032fa3d..00000000 --- a/src/Samples/TestStack.BDDfy.Samples/BuyingTrainFares/Money.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System.Globalization; - -namespace TestStack.BDDfy.Samples.BuyingTrainFares -{ - class Money(decimal amount) - { - public decimal Amount { get; set; } = amount; - - protected bool Equals(Money other) - { - return Amount == other.Amount; - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != GetType()) return false; - return Equals((Money)obj); - } - - public override int GetHashCode() - { - return Amount.GetHashCode(); - } - - public static bool operator ==(Money left, Money right) - { - return Equals(left, right); - } - - public static bool operator !=(Money left, Money right) - { - return !Equals(left, right); - } - - public override string ToString() - { - return Amount.ToString("C", new CultureInfo("EN-US")); - } - } -} \ No newline at end of file diff --git a/src/Samples/TestStack.BDDfy.Samples/BuyingTrainFares/MonthlyPass.cs b/src/Samples/TestStack.BDDfy.Samples/BuyingTrainFares/MonthlyPass.cs deleted file mode 100644 index 09ac243b..00000000 --- a/src/Samples/TestStack.BDDfy.Samples/BuyingTrainFares/MonthlyPass.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace TestStack.BDDfy.Samples.BuyingTrainFares -{ - class MonthlyPass : Fare - { - public override string ToString() - { - return "Monthly Pass"; - } - } -} \ No newline at end of file diff --git a/src/Samples/TestStack.BDDfy.Samples/BuyingTrainFares/SingleTicket.cs b/src/Samples/TestStack.BDDfy.Samples/BuyingTrainFares/SingleTicket.cs deleted file mode 100644 index 60ca4eaf..00000000 --- a/src/Samples/TestStack.BDDfy.Samples/BuyingTrainFares/SingleTicket.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace TestStack.BDDfy.Samples.BuyingTrainFares -{ - class SingleTicket : Fare - { - public override string ToString() - { - return "Day Pass"; - } - } -} \ No newline at end of file diff --git a/src/Samples/TestStack.BDDfy.Samples/BuyingTrainFares/WeeklyPass.cs b/src/Samples/TestStack.BDDfy.Samples/BuyingTrainFares/WeeklyPass.cs deleted file mode 100644 index fc9a511e..00000000 --- a/src/Samples/TestStack.BDDfy.Samples/BuyingTrainFares/WeeklyPass.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace TestStack.BDDfy.Samples.BuyingTrainFares -{ - class WeeklyPass : Fare - { - public override string ToString() - { - return "Weekly Pass"; - } - } -} \ No newline at end of file diff --git a/src/Samples/TestStack.BDDfy.Samples/CanRunAsyncSteps.cs b/src/Samples/TestStack.BDDfy.Samples/CanRunAsyncSteps.cs deleted file mode 100644 index 1025b3a3..00000000 --- a/src/Samples/TestStack.BDDfy.Samples/CanRunAsyncSteps.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Threading.Tasks; -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Samples -{ - public class CanRunAsyncSteps - { - private Sut _sut; - - internal async void GivenSomeAsyncSetup() - { - _sut = await CreateSut(); - } - - internal void ThenBddfyHasWaitedForThatSetupToCompleteBeforeContinuing() - { - _sut.ShouldNotBe(null); - } - - internal async Task AndThenBddfyShouldCaptureExceptionsThrownInAsyncMethod() - { - await Task.Yield(); - throw new Exception("Exception in async void method!!"); - } - - private async Task CreateSut() - { - await Task.Delay(500); - return new Sut(); - } - - [Fact] - public void Run() - { - var engine = this.LazyBDDfy(); - var exception = Should.Throw(() => engine.Run()); - - exception.Message.ShouldBe("Exception in async void method!!"); - } - - internal class Sut - { - } - } -} \ No newline at end of file diff --git a/src/Samples/TestStack.BDDfy.Samples/CanWorkWithoutAStory.cs b/src/Samples/TestStack.BDDfy.Samples/CanWorkWithoutAStory.cs deleted file mode 100644 index ac41d335..00000000 --- a/src/Samples/TestStack.BDDfy.Samples/CanWorkWithoutAStory.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Xunit; - -namespace TestStack.BDDfy.Samples -{ - public class CanWorkWithoutAStory - { - internal void Given_no_story_is_provided() - { - } - - internal void When_we_BDDfy_the_class() - { - } - - internal void Then_the_namespace_is_used_in_the_report() - { - } - - [Fact] - public void Execute() - { - this.BDDfy(); - } - } -} diff --git a/src/Samples/TestStack.BDDfy.Samples/CustomTextReporter.cs b/src/Samples/TestStack.BDDfy.Samples/CustomTextReporter.cs deleted file mode 100644 index 5293448a..00000000 --- a/src/Samples/TestStack.BDDfy.Samples/CustomTextReporter.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Text; - -namespace TestStack.BDDfy.Samples -{ - /// - /// This is a custom reporter that shows you how easily you can create a custom report. - /// Just implemented IProcessor and you are done - /// - public class CustomTextReporter : IProcessor - { - private static readonly string Path; - - private static string OutputDirectory - { - get - { - string codeBase = typeof(CustomTextReporter).GetTypeInfo().Assembly.Location; - return System.IO.Path.GetDirectoryName(codeBase); - } - } - - static CustomTextReporter() - { - Path = System.IO.Path.Combine(OutputDirectory, "BDDfy-text-report.txt"); - - if(File.Exists(Path)) - File.Delete(Path); - - var header = - " A custom report created from your test assembly with no required configuration " + - Environment.NewLine + - Environment.NewLine + - Environment.NewLine + - Environment.NewLine; - File.AppendAllText(Path, header); - } - - public void Process(Story story) - { - // use this report only for tic tac toe stories - if (story.Metadata == null || !story.Metadata.Type.Name.Contains("TicTacToe")) - return; - - var scenario = story.Scenarios.First(); - var scenarioReport = new StringBuilder(); - scenarioReport.AppendLine(string.Format(" SCENARIO: {0} ", scenario.Title)); - - if (scenario.Result != Result.Passed && scenario.Steps.Any(s => s.Exception != null)) - { - scenarioReport.Append(string.Format(" {0} : ", scenario.Result)); - scenarioReport.AppendLine(scenario.Steps.First(s => s.Result == scenario.Result).Exception.Message); - } - - scenarioReport.AppendLine(); - - foreach (var step in scenario.Steps) - scenarioReport.AppendLine(string.Format(" [{1}] {0}", step.Title, step.Result)); - - scenarioReport.AppendLine("--------------------------------------------------------------------------------"); - scenarioReport.AppendLine(); - - File.AppendAllText(Path, scenarioReport.ToString()); - } - - public ProcessType ProcessType - { - get { return ProcessType.Report; } - } - } -} \ No newline at end of file diff --git a/src/Samples/TestStack.BDDfy.Samples/TestStack.BDDfy.Samples.csproj b/src/Samples/TestStack.BDDfy.Samples/TestStack.BDDfy.Samples.csproj deleted file mode 100644 index 8a150d91..00000000 --- a/src/Samples/TestStack.BDDfy.Samples/TestStack.BDDfy.Samples.csproj +++ /dev/null @@ -1,31 +0,0 @@ - - - - net8.0 - TestStack.BDDfy.Samples - TestStack.BDDfy.Samples - true - false - false - false - - - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - diff --git a/src/Samples/TestStack.BDDfy.Samples/TicTacToe/Game.cs b/src/Samples/TestStack.BDDfy.Samples/TicTacToe/Game.cs deleted file mode 100644 index 3a9ba31f..00000000 --- a/src/Samples/TestStack.BDDfy.Samples/TicTacToe/Game.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -namespace TestStack.BDDfy.Samples.TicTacToe -{ - public class Game - { - public const string X = "X"; - public const string O = "O"; - public const string N = " "; - - private static readonly string[] EmptyRow = Enumerable.Repeat(N, 3).ToArray(); - readonly string[][] _board; - - public Game() - : this(EmptyRow, EmptyRow, EmptyRow) - { - } - - public Game(string[] firstRow, string[] secondRow, string[] thirdRow) - { - _board = new string[3][]; - _board[0] = (string[])firstRow.Clone(); - _board[1] = (string[])secondRow.Clone(); - _board[2] = (string[])thirdRow.Clone(); - } - - public string Winner - { - get - { - var winnerLine = Lines.FirstOrDefault(line => line.All(l => l == X) || line.All(l => l == O)); - if (winnerLine == null) - return null; - - return winnerLine.First(); - } - } - - IEnumerable Lines - { - get - { - for (int i = 0; i < 3; i++) - { - yield return new[] { _board[i][0], _board[i][1], _board[i][2] }; - yield return new[] { _board[0][i], _board[1][i], _board[2][i] }; - } - - yield return new[] { _board[0][0], _board[1][1], _board[2][2] }; - yield return new[] { _board[2][0], _board[1][1], _board[0][2] }; - } - } - - public void PlayAt(int row, int column) - { - var emptyCellsCount = _board.SelectMany(s=>s).Count(s => s == N); - var player = X; - if (emptyCellsCount % 2 == 0) - player = O; - - _board[row][column] = player; - } - - public override bool Equals(object obj) - { - var game = obj as Game; - return game != null && base.Equals(game); - } - - public bool Equals(Game other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - - for (int i = 0; i < 3; i++) - { - if(!_board[i].SequenceEqual(other._board[i])) - return false; - } - - return true; - } - - public override int GetHashCode() - { - return (_board != null ? _board.GetHashCode() : 0); - } - } -} \ No newline at end of file diff --git a/src/Samples/TestStack.BDDfy.Samples/TicTacToe/Helpers.cs b/src/Samples/TestStack.BDDfy.Samples/TicTacToe/Helpers.cs deleted file mode 100644 index 98d1876c..00000000 --- a/src/Samples/TestStack.BDDfy.Samples/TicTacToe/Helpers.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Shouldly; - -namespace TestStack.BDDfy.Samples.TicTacToe -{ - public static class Helpers - { - public static void VerifyBoardState(this Game game, string[] firstRow, string[] secondRow, string[] thirdRow) - { - game.Equals(new Game(firstRow, secondRow, thirdRow)).ShouldBe(true); - } - } - - public class GameUnderTest - { - protected const string BoardStateTemplate = "Given the board\r\n{0}\r\n{1}\r\n{2}"; - - protected const string X = Game.X; - protected const string O = Game.O; - protected const string N = Game.N; - - protected Game Game { get; set; } - } - - public abstract class NewGame : GameUnderTest - { - protected void GivenANewGame() - { - Game = new Game(); - } - } -} \ No newline at end of file diff --git a/src/Samples/TestStack.BDDfy.Samples/TicTacToe/TicTacToe.cs b/src/Samples/TestStack.BDDfy.Samples/TicTacToe/TicTacToe.cs deleted file mode 100644 index 726295a3..00000000 --- a/src/Samples/TestStack.BDDfy.Samples/TicTacToe/TicTacToe.cs +++ /dev/null @@ -1,99 +0,0 @@ -using Shouldly; -using Xunit; -using Xunit.Extensions; - -namespace TestStack.BDDfy.Samples.TicTacToe -{ - [Story( - AsA = "As a player", - IWant = "I want to have a tic tac toe game", - SoThat = "So that I can waste some time!")] - public class TicTacToe : NewGame - { - class Cell(int row, int col) - { - public int Row { get; set; } = row; - public int Col { get; set; } = col; - - public override string ToString() - { - return string.Format("({0}, {1})", Row, Col); - } - } - - void GivenTheFollowingBoard(string[] firstRow, string[] secondRow, string[] thirdrow) - { - Game = new Game(firstRow, secondRow, thirdrow); - } - - void ThenTheBoardStateShouldBe(string[] firstRow, string[] secondRow, string[] thirdrow) - { - Game.VerifyBoardState(firstRow, secondRow, thirdrow); - } - - void ThenTheWinnerShouldBe(string expectedWinner) - { - Game.Winner.ShouldBe(expectedWinner); - } - - void ThenItShouldBeACatsGame() - { - Game.Winner.ShouldBe(null); - } - - void WhenTheGameIsPlayedAt(params Cell[] cells) - { - foreach (var cell in cells) - { - Game.PlayAt(cell.Row, cell.Col); - } - } - - [Fact] - public void CatsGame() - { - this.Given(s => s.GivenTheFollowingBoard(new[] { X, O, X }, new[] { O, O, X }, new[] { X, X, O }), BoardStateTemplate) - .Then(s => s.ThenItShouldBeACatsGame()) - .BDDfy("Cat's game"); - } - - [Fact] - public void WhenXAndOPlayTheirFirstMoves() - { - this.Given(s => s.GivenANewGame()) - .When(s => s.WhenTheGameIsPlayedAt(new Cell(0, 0), new Cell(2, 2)), "When X and O play on {0}") - .Then(s => s.ThenTheBoardStateShouldBe(new[] { X, N, N }, new[] { N, N, N }, new[] { N, N, O })) - .BDDfy(); - } - - [Fact] - public void OWins() - { - var cell = new Cell(2, 0); - this.Given(s => s.GivenTheFollowingBoard(new[] { X, X, O }, new[] { X, O, N }, new[] { N, N, N })) - .When(s => s.WhenTheGameIsPlayedAt(cell)) - .Then(s => s.ThenTheWinnerShouldBe(O)) - .BDDfy(); - } - - [Fact] - public void XWins() - { - // This is implemented like this to show you the possibilities - new XWins().BDDfy(); - } - - [Theory] - [InlineData("Vertical win in the right", new[] { X, O, X }, new[] { O, O, X }, new[] { O, X, X }, X)] - [InlineData("Vertical win in the middle", new[] { N, X, O }, new[] { O, X, O }, new[] { O, X, X }, X)] - [InlineData("Diagonal win", new[] { X, O, O }, new[] { X, O, X }, new[] { O, X, N }, O)] - [InlineData("Horizontal win in the bottom", new[] { X, X, N }, new[] { X, O, X }, new[] { O, O, O }, O)] - [InlineData("Horizontal win in the middle", new[] { X, O, O }, new[] { X, X, X }, new[] { O, O, X }, X)] - [InlineData("Vertical win in the left", new[] { X, O, O }, new[] { X, O, X }, new[] { X, X, O }, X)] - [InlineData("Horizontal win", new[] { X, X, X }, new[] { X, O, O }, new[] { O, O, X }, X)] - public void WinnerGame(string title, string[] firstRow, string[] secondRow, string[] thirdRow, string expectedWinner) - { - new WinnerGame(firstRow, secondRow, thirdRow, expectedWinner).BDDfy(title); - } - } -} diff --git a/src/Samples/TestStack.BDDfy.Samples/TicTacToe/WinnerGame.cs b/src/Samples/TestStack.BDDfy.Samples/TicTacToe/WinnerGame.cs deleted file mode 100644 index 43e363eb..00000000 --- a/src/Samples/TestStack.BDDfy.Samples/TicTacToe/WinnerGame.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Collections.Generic; -using NUnit.Framework; -using Shouldly; - -namespace TestStack.BDDfy.Samples.TicTacToe -{ - public class WinnerGame(string[] firstRow, string[] secondRow, string[] thirdRow, string expectedWinner): GameUnderTest - { - private readonly string[] _firstRow = firstRow; - private readonly string[] _secondRow = secondRow; - private readonly string[] _thirdRow = thirdRow; - private readonly string _expectedWinner = expectedWinner; - - // Note: This method returns IEnumerable - // this is done to allow the method to return its title. - // if you use this method make sure to yield return the title as the very first action - IEnumerable GivenTheFollowingBoard() - { - yield return string.Format( - BoardStateTemplate, - string.Join(", ", _firstRow), - string.Join(", ", _secondRow), - string.Join(", ", _thirdRow)); - - Game = new Game(_firstRow, _secondRow, _thirdRow); - } - - // Note: This method returns IEnumerable - // this is done to allow the method to return its title. - // if you use this method make sure to yield return the title as the very first action - IEnumerable ThenTheWinnerShouldBe() - { - yield return "Then the winner is " + _expectedWinner; - Game.Winner.ShouldBe(_expectedWinner); - } - } -} \ No newline at end of file diff --git a/src/Samples/TestStack.BDDfy.Samples/TicTacToe/XWins.cs b/src/Samples/TestStack.BDDfy.Samples/TicTacToe/XWins.cs deleted file mode 100644 index 304facd2..00000000 --- a/src/Samples/TestStack.BDDfy.Samples/TicTacToe/XWins.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Shouldly; - -namespace TestStack.BDDfy.Samples.TicTacToe -{ - public class XWins : GameUnderTest - { - [RunStepWithArgs( - new[] { X, X, O }, - new[] { X, X, O }, - new[] { O, O, N }, - StepTextTemplate = BoardStateTemplate)] - void GivenTheFollowingBoard(string[] firstRow, string[] secondRow, string[] thirdRow) - { - Game = new Game(firstRow, secondRow, thirdRow); - } - - void WhenXPlaysInTheBottomRight() - { - Game.PlayAt(2, 2); - } - - void ThenTheWinnerShouldBeX() - { - Game.Winner.ShouldBe(X); - } - } -} \ No newline at end of file diff --git a/src/Samples/TestStack.BDDfy.Samples/UseExamplesWithFluentApi.cs b/src/Samples/TestStack.BDDfy.Samples/UseExamplesWithFluentApi.cs deleted file mode 100644 index 19cd6603..00000000 --- a/src/Samples/TestStack.BDDfy.Samples/UseExamplesWithFluentApi.cs +++ /dev/null @@ -1,53 +0,0 @@ -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Samples -{ - public class UseExamplesWithFluentApi - { - public int Start { get; set; } - public int Eat { get; set; } - public int Left { get; set; } - - [Fact] - public void RunExamplesWithFluentApi() - { - this.Given("Given there are cucumbers") - .And(_ => _.AndIStealTwoMore()) - .When(_ => _.WhenIEat__eat__Cucumbers()) - .Then(_ => _.ThenIShouldHave__left__Cucumbers()) - .WithExamples(new ExampleTable("Start", "Eat", "Left") - { - {12, 5, 9}, - {20, 5, 17} - }) - .BDDfy(); - } - - - // I didn't have to create this method - // because all it was going to do was to set Start property - // which is being handled by the framework - // And the step title is provided inline - //private void GivenThereAre__start__Cucumbers() - //{ - //} - - private void AndIStealTwoMore() - { - Start += 2; - } - - private void WhenIEat__eat__Cucumbers() - { - // This method is called after the Eat property is set by the framework - // I didn't have to put this here, like the Given method, but I put it here to show that - // you can take additional actions here if you want - } - - private void ThenIShouldHave__left__Cucumbers() - { - (Start - Eat).ShouldBe(Left); - } - } -} diff --git a/src/Samples/TestStack.BDDfy.Samples/UseExamplesWithReflectiveApi.cs b/src/Samples/TestStack.BDDfy.Samples/UseExamplesWithReflectiveApi.cs deleted file mode 100644 index 0f1e77e4..00000000 --- a/src/Samples/TestStack.BDDfy.Samples/UseExamplesWithReflectiveApi.cs +++ /dev/null @@ -1,45 +0,0 @@ -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Samples -{ - public class UseExamplesWithReflectiveApi - { - private int _start; - private int _eat; - - [Fact] - public void CanRunExamplesWithReflectiveApi() - { - this.WithExamples(new ExampleTable("Start", "Eat", "Left") - { - {12, 5, 7}, - {20, 5, 15} - }) - .BDDfy(); - } - - void GivenThereAre__start__Cucumbers(int start) - { - // the start argument is provided by the framework based on the example entries - // please note that `start` argument name matches the `start` header from the examples - // and also it has to match with the placeholder in the step title which is created based on conventions - _start = start; - } - - [AndGiven("And I eat of them")] - void WhenIEatAFewCucumbers(int eat) - { - // the eat argument is provided by the framework based on the example entries - // please note that `eat` argument name matches the `start` header from the examples - // and also it has to match the placeholder in the step title - _eat = eat; - } - - void ThenIShouldHave__left__Cucumbers(int left) - { - // like given and when steps left is provided here because it matches the example header and is found on the step title - (_start - _eat).ShouldBe(left); - } - } -} diff --git a/src/TestStack.BDDfy.Tests/Arguments/ArgumentsProvidedForGiven.cs b/src/TestStack.BDDfy.Tests/Arguments/ArgumentsProvidedForGiven.cs deleted file mode 100644 index cc6bb5a8..00000000 --- a/src/TestStack.BDDfy.Tests/Arguments/ArgumentsProvidedForGiven.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System.Collections.Generic; -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Tests.Arguments -{ - public class ArgumentsProvidedForGiven - { - private readonly List _andGivenInput1 = new(); - private List _andGivenInput2 = new(); - private List _andGivenInput3 = new(); - - private int _givenInput3; - private int _givenInput2; - private int _givenInput1; - - [RunStepWithArgs(1, 2, 3)] - void GivenOneSetOfArgumentsAreProvidedForGivenPart(int input1, int input2, int input3) - { - _givenInput1 = input1; - _givenInput2 = input2; - _givenInput3 = input3; - } - - [RunStepWithArgs(4, 5, 6)] - [RunStepWithArgs(7, 8, 9)] - void GivenMoreThanOneSetOfArgumentsAreProvidedForGivenPart(int input1, int input2, int input3) - { - _andGivenInput1.Add(input1); - _andGivenInput2.Add(input2); - _andGivenInput3.Add(input3); - } - - void ThenOneSetOfArgumentsArePassedInProperly() - { - _givenInput1.ShouldBe(1); - _givenInput2.ShouldBe(2); - _givenInput3.ShouldBe(3); - } - - void ThenSeveralSetsOfArgumentsArePassedInProperly() - { - _andGivenInput1.Count.ShouldBe(2); - _andGivenInput1.ShouldContain(4); - _andGivenInput1.ShouldContain(7); - - _andGivenInput2.Count.ShouldBe(2); - _andGivenInput2.ShouldContain(5); - _andGivenInput2.ShouldContain(8); - - _andGivenInput3.Count.ShouldBe(2); - _andGivenInput3.ShouldContain(6); - _andGivenInput3.ShouldContain(9); - } - - [Fact] - public void Execute() - { - this.BDDfy(); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Arguments/ArgumentsProvidedForThen.cs b/src/TestStack.BDDfy.Tests/Arguments/ArgumentsProvidedForThen.cs deleted file mode 100644 index 3cbe11b1..00000000 --- a/src/TestStack.BDDfy.Tests/Arguments/ArgumentsProvidedForThen.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Tests.Arguments -{ - public class ArgumentsProvidedForThen - { - void GivenArgumentsAreProvidedForThenPart() - { - } - - [RunStepWithArgs(1, "Test")] - void ThenArgumentsAreSentToThenPart(int argument1, string argument2) - { - argument1.ShouldBe(1); - argument2.ShouldBe("Test"); - } - - [Fact] - public void Execute() - { - this.BDDfy(); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Arguments/MultipleArgumentsProvidedForTheSameStep.cs b/src/TestStack.BDDfy.Tests/Arguments/MultipleArgumentsProvidedForTheSameStep.cs deleted file mode 100644 index 893b13c9..00000000 --- a/src/TestStack.BDDfy.Tests/Arguments/MultipleArgumentsProvidedForTheSameStep.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Collections.Generic; -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Tests.Arguments -{ - public class MultipleArgumentsProvidedForTheSameStep - { - private readonly List _inputs = new(); - - [RunStepWithArgs(1)] - [RunStepWithArgs(2)] - [RunStepWithArgs(3)] - void GivenMultipleArgumentAttributesAreProvidedToSameMethod(int input) - { - _inputs.Add(input); - } - - void ThenTheMethodIsCalledOncePerArgument() - { - _inputs.Count.ShouldBe(3); - _inputs.ShouldContain(1); - _inputs.ShouldContain(2); - _inputs.ShouldContain(3); - } - - [Fact] - public void Execute() - { - this.BDDfy(); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Concurrency/ParallelRunnerScenario.cs b/src/TestStack.BDDfy.Tests/Concurrency/ParallelRunnerScenario.cs deleted file mode 100644 index 700e1b7e..00000000 --- a/src/TestStack.BDDfy.Tests/Concurrency/ParallelRunnerScenario.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Linq; -using System.Threading.Tasks; -using TestStack.BDDfy.Tests.Stories; -using Xunit; - -namespace TestStack.BDDfy.Tests.Concurrency -{ - public class ParallelRunnerScenario - { - [Fact] - public async Task CanHandleMultipleThreadsExecutingBddfyConcurrently() - { - await Task.WhenAll( - Enumerable.Range(0, 100) - .Select(_ => Task.Run(() => new DummyScenario().BDDfy()))); - } - } -} diff --git a/src/TestStack.BDDfy.Tests/Configuration/BatchProcessorsTests.cs b/src/TestStack.BDDfy.Tests/Configuration/BatchProcessorsTests.cs deleted file mode 100644 index b6ac86f7..00000000 --- a/src/TestStack.BDDfy.Tests/Configuration/BatchProcessorsTests.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System.Linq; -using Shouldly; -using TestStack.BDDfy.Configuration; -using TestStack.BDDfy.Reporters.Html; -using TestStack.BDDfy.Reporters.MarkDown; -using Xunit; - -namespace TestStack.BDDfy.Tests.Configuration -{ - public class BatchProcessorsTests - { - static bool MetroReportProcessorIsActive(IBatchProcessor batchProcessor) - { - return batchProcessor is HtmlReporter && ((HtmlReporter)batchProcessor).ReportBuilder is MetroReportBuilder; - } - - [Fact] - public void ReturnsHtmlReporterByDefault() - { - var processors = Configurator.BatchProcessors.GetProcessors().ToList(); - processors.Any(p => p is HtmlReporter).ShouldBe(true); - } - - [Fact] - public void DoesNotReturnMarkDownReporterByDefault() - { - var processors = Configurator.BatchProcessors.GetProcessors().ToList(); - processors.Any(p => p is MarkDownReporter).ShouldBe(false); - } - - [Fact] - public void DoesNotReturnHtmlMetroReporterByDefault() - { - var processors = Configurator.BatchProcessors.GetProcessors().ToList(); - processors.Any(MetroReportProcessorIsActive).ShouldBe(false); - } - - [Fact] - public void DoesNotReturnHtmlReporterWhenItIsDeactivated() - { - Configurator.BatchProcessors.HtmlReport.Disable(); - - var processors = Configurator.BatchProcessors.GetProcessors().ToList(); - processors.Any(p => p is HtmlReporter).ShouldBe(false); - - Configurator.BatchProcessors.HtmlReport.Enable(); - } - - [Fact] - public void ReturnsMarkdownReporterWhenItIsActivated() - { - Configurator.BatchProcessors.MarkDownReport.Enable(); - - var processors = Configurator.BatchProcessors.GetProcessors().ToList(); - processors.Any(p => p is MarkDownReporter).ShouldBe(true); - - Configurator.BatchProcessors.MarkDownReport.Disable(); - } - - [Fact] - public void ReturnsHtmlMetroReporterWhenItIsActivated() - { - Configurator.BatchProcessors.HtmlMetroReport.Enable(); - - var processors = Configurator.BatchProcessors.GetProcessors().ToList(); - processors.Any(MetroReportProcessorIsActive).ShouldBe(true); - - Configurator.BatchProcessors.HtmlMetroReport.Disable(); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Configuration/CustomProcessor.cs b/src/TestStack.BDDfy.Tests/Configuration/CustomProcessor.cs deleted file mode 100644 index 9ebe2edb..00000000 --- a/src/TestStack.BDDfy.Tests/Configuration/CustomProcessor.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace TestStack.BDDfy.Tests.Configuration -{ - public class CustomProcessor : IProcessor - { - public ProcessType ProcessType - { - get { return ProcessType.BeforeReport; } - } - - public void Process(Story story) - { - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Configuration/EmptyScenario.cs b/src/TestStack.BDDfy.Tests/Configuration/EmptyScenario.cs deleted file mode 100644 index afd27c26..00000000 --- a/src/TestStack.BDDfy.Tests/Configuration/EmptyScenario.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace TestStack.BDDfy.Tests.Configuration -{ - public class EmptyScenario - { - public void GivenSomething() { } - public void WhenSomething() { } - public void ThenSomething() { } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Configuration/ProcessorPipelineTests.cs b/src/TestStack.BDDfy.Tests/Configuration/ProcessorPipelineTests.cs deleted file mode 100644 index 3ca8a1ab..00000000 --- a/src/TestStack.BDDfy.Tests/Configuration/ProcessorPipelineTests.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System.Linq; -using Shouldly; -using TestStack.BDDfy.Configuration; -using TestStack.BDDfy.Processors; -using TestStack.BDDfy.Reporters; -using Xunit; - -namespace TestStack.BDDfy.Tests.Configuration -{ - [Collection("ExclusiveAccessToConfigurator")] - public class ProcessorPipelineTests - { - [Fact] - public void ReturnsDefaultPipelineByDefault() - { - var processors = Configurator.Processors.GetProcessors(new Story(null)).ToList(); - - processors.Any(p => p is ConsoleReporter).ShouldBe(true); - processors.Any(p => p is StoryCache).ShouldBe(true); - processors.Any(p => p is TestRunner).ShouldBe(true); - processors.Any(p => p is ExceptionProcessor).ShouldBe(true); - } - - [Fact] - public void DoesNotReturnConsoleReportWhenItIsDeactivated() - { - Configurator.Processors.ConsoleReport.Disable(); - var processors = Configurator.Processors.GetProcessors(new Story(null)).ToList(); - - processors.Any(p => p is ConsoleReporter).ShouldBe(false); - processors.Any(p => p is StoryCache).ShouldBe(true); - processors.Any(p => p is TestRunner).ShouldBe(true); - processors.Any(p => p is ExceptionProcessor).ShouldBe(true); - Configurator.Processors.ConsoleReport.Enable(); - } - - [Fact] - public void DoesNotReturnConsoleReportForExcludedStories() - { - Configurator.Processors.ConsoleReport.RunsOn(s => s.Metadata != null); - var processors = Configurator.Processors.GetProcessors(new Story(null)).ToList(); - - processors.Any(p => p is ConsoleReporter).ShouldBe(false); - Configurator.Processors.ConsoleReport.RunsOn(s => true); - } - - [Fact] - public void DoesNotReturnTestRunnerWhenItIsDeactivated() - { - Configurator.Processors.TestRunner.Disable(); - var processors = Configurator.Processors.GetProcessors(new Story(null)).ToList(); - - processors.Any(p => p is ConsoleReporter).ShouldBe(true); - processors.Any(p => p is TestRunner).ShouldBe(false); - processors.Any(p => p is StoryCache).ShouldBe(true); - processors.Any(p => p is ExceptionProcessor).ShouldBe(true); - Configurator.Processors.TestRunner.Enable(); - } - - [Fact] - public void CanAddCustomProcessor() - { - var processors = Configurator - .Processors - .Add(() => new CustomProcessor()) - .GetProcessors(new Story(null)).ToList(); - - processors.Any(p => p is CustomProcessor).ShouldBe(true); - processors.Any(p => p is StoryCache).ShouldBe(true); - processors.Any(p => p is ConsoleReporter).ShouldBe(true); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Configuration/SequentialKeyGeneratorTests.cs b/src/TestStack.BDDfy.Tests/Configuration/SequentialKeyGeneratorTests.cs deleted file mode 100644 index ad2501cd..00000000 --- a/src/TestStack.BDDfy.Tests/Configuration/SequentialKeyGeneratorTests.cs +++ /dev/null @@ -1,53 +0,0 @@ -using Shouldly; -using TestStack.BDDfy.Configuration; -using Xunit; - -namespace TestStack.BDDfy.Tests.Configuration -{ - public class SequentialKeyGeneratorTests - { - [Fact] - public void ShouldReturnOneForFirstScenario() - { - new SequentialKeyGenerator().GetScenarioId().ShouldBe("scenario-1"); - } - - [Fact] - public void ShouldIncrementScenarioIdForEachRequestForScenariId() - { - var sut = new SequentialKeyGenerator(); - - for (int i = 1; i <= 12; i++) - { - sut.GetScenarioId().ShouldBe("scenario-" + i); - } - } - - [Fact] - public void ShouldReturnOneOneForFirstStepOfFirstScenario() - { - new SequentialKeyGenerator().GetStepId().ShouldBe("step-1-1"); - } - - [Fact] - public void ShouldIncrementStepIdForEachRequestForStepId() - { - var sut = new SequentialKeyGenerator(); - - for (int i = 1; i <= 12; i++) - { - sut.GetStepId().ShouldBe("step-1-" + i); - } - } - - [Fact] - public void ShouldResetStepCountForNewScenario() - { - var sut = new SequentialKeyGenerator(); - sut.GetStepId(); - sut.GetScenarioId(); - - sut.GetStepId().ShouldBe("step-2-1"); - } - } -} diff --git a/src/TestStack.BDDfy.Tests/Configuration/StepExecutorTests.cs b/src/TestStack.BDDfy.Tests/Configuration/StepExecutorTests.cs deleted file mode 100644 index 8d9e1916..00000000 --- a/src/TestStack.BDDfy.Tests/Configuration/StepExecutorTests.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System.Text; -using Shouldly; -using TestStack.BDDfy.Configuration; -using Xunit; - -namespace TestStack.BDDfy.Tests.Configuration -{ - [Collection("ExclusiveAccessToConfigurator")] - public class StepExecutorTests - { - private class TestStepExecutor : StepExecutor - { - readonly StringBuilder _builder = new(); - - public string Results - { - get { return _builder.ToString(); } - } - - public override object Execute(Step step, object testObject) - { - try - { - _builder.AppendLine(string.Format("About to run step '{0}'", step.Title)); - return base.Execute(step, testObject); - } - finally - { - _builder.AppendLine(string.Format("Finished running step '{0}'", step.Title)); - } - } - } - - [Fact] - public void CustomizingStepExecutionByOverridingStepExecutor() - { - try - { - var testStepExecutor = new TestStepExecutor(); - - Configurator.StepExecutor = testStepExecutor; - - new EmptyScenario() - .Given(s => s.GivenSomething()) - .When(s => s.WhenSomething()) - .Then(s => s.ThenSomething()) - .BDDfy(); - - string expected = -@"About to run step 'Given something' -Finished running step 'Given something' -About to run step 'When something' -Finished running step 'When something' -About to run step 'Then something' -Finished running step 'Then something' -".Replace("\r", string.Empty).Trim(); - - testStepExecutor.Results.Replace("\r", string.Empty).Trim().ShouldBe(expected); - } - finally - { - Configurator.StepExecutor = new StepExecutor(); - } - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Configuration/TestRunnerTests.cs b/src/TestStack.BDDfy.Tests/Configuration/TestRunnerTests.cs deleted file mode 100644 index f89aece7..00000000 --- a/src/TestStack.BDDfy.Tests/Configuration/TestRunnerTests.cs +++ /dev/null @@ -1,138 +0,0 @@ -using System; -using System.Linq; -using Shouldly; -using TestStack.BDDfy.Configuration; -using Xunit; - -namespace TestStack.BDDfy.Tests.Configuration -{ - [Collection("ExclusiveAccessToConfigurator")] - public class TestRunnerTests - { - public class ScenarioWithFailingThen - { - [Given] - public void PassingGiven() - { - } - - [When] - public void PassingWhen() - { - } - - [Then] - public void FailingThen() - { - throw new Exception(); - } - - [AndThen] - public void PassingAndThen() - { - } - } - - public class When_StopExecutionOnFailingThen_IsSetToTrue - { - [Fact] - public void FailingThenStopsThePipelineWithReflectiveAPI() - { - Configurator.Processors.TestRunner.StopExecutionOnFailingThen = true; - - try - { - var testRun = new ScenarioWithFailingThen().LazyBDDfy(); - Verify(testRun); - } - finally - { - Configurator.Processors.TestRunner.StopExecutionOnFailingThen = false; - } - } - - [Fact] - public void FailingThenStopsThePipelineWithFluentAPI() - { - Configurator.Processors.TestRunner.StopExecutionOnFailingThen = true; - - try - { - var testRun = new ScenarioWithFailingThen() - .Given(x => x.PassingGiven()) - .When(x => x.PassingWhen()) - .Then(x => x.FailingThen()) - .And(x => x.PassingAndThen()) - .LazyBDDfy(); - - Verify(testRun); - } - finally - { - Configurator.Processors.TestRunner.StopExecutionOnFailingThen = false; - } - } - - private static void Verify(Engine testRun) - { - Should.Throw(() => testRun.Run()); - var scenario = testRun.Story.Scenarios.First(); - scenario.Result.ShouldBe(Result.Failed); - var steps = scenario.Steps; - - steps.Count.ShouldBe(4); - steps[0].Result.ShouldBe(Result.Passed); - steps[0].ExecutionOrder.ShouldBe(ExecutionOrder.SetupState); - steps[1].Result.ShouldBe(Result.Passed); - steps[1].ExecutionOrder.ShouldBe(ExecutionOrder.Transition); - steps[2].Result.ShouldBe(Result.Failed); - steps[2].ExecutionOrder.ShouldBe(ExecutionOrder.Assertion); - steps[3].Result.ShouldBe(Result.NotExecuted); - steps[3].ExecutionOrder.ShouldBe(ExecutionOrder.ConsecutiveAssertion); - } - } - - public class When_StopExecutionOnFailingThen_IsLeftAsDefault - { - [Fact] - public void FailingThenDoesNotStopThePipelineWithReflectiveAPI() - { - var testRun = new ScenarioWithFailingThen().LazyBDDfy(); - Verify(testRun); - } - - [Fact] - public void FailingThenDoesNotStopThePipelineWithFluentAPI() - { - Configurator.Processors.TestRunner.StopExecutionOnFailingThen = false; - - var testRun = new ScenarioWithFailingThen() - .Given(x => x.PassingGiven()) - .When(x => x.PassingWhen()) - .Then(x => x.FailingThen()) - .And(x => x.PassingAndThen()) - .LazyBDDfy(); - - Verify(testRun); - } - - private static void Verify(Engine testRun) - { - Should.Throw(() => testRun.Run()); - var scenario = testRun.Story.Scenarios.First(); - scenario.Result.ShouldBe(Result.Failed); - var steps = scenario.Steps; - - steps.Count.ShouldBe(4); - steps[0].Result.ShouldBe(Result.Passed); - steps[0].ExecutionOrder.ShouldBe(ExecutionOrder.SetupState); - steps[1].Result.ShouldBe(Result.Passed); - steps[1].ExecutionOrder.ShouldBe(ExecutionOrder.Transition); - steps[2].Result.ShouldBe(Result.Failed); - steps[2].ExecutionOrder.ShouldBe(ExecutionOrder.Assertion); - steps[3].Result.ShouldBe(Result.Passed); - steps[3].ExecutionOrder.ShouldBe(ExecutionOrder.ConsecutiveAssertion); - } - } - } -} diff --git a/src/TestStack.BDDfy.Tests/DefaultHumanizerTests.cs b/src/TestStack.BDDfy.Tests/DefaultHumanizerTests.cs deleted file mode 100644 index 7a5d7baf..00000000 --- a/src/TestStack.BDDfy.Tests/DefaultHumanizerTests.cs +++ /dev/null @@ -1,86 +0,0 @@ -using System; -using Shouldly; -using TestStack.BDDfy.Configuration; -using Xunit; - -namespace TestStack.BDDfy.Tests -{ - public class DefaultHumanizerTests - { - private static DefaultHumanizer Humanizer => new(); - - [Fact] - public void PascalCaseInputStringIsTurnedIntoSentence() - { - Humanizer.Humanize("PascalCaseInputStringIsTurnedIntoSentence") - .ShouldBe("Pascal case input string is turned into sentence"); - } - - [Fact] - public void WhenInputStringContainsConsequtiveCaptialLetters_ThenTheyAreTurnedIntoOneLetterWords() - { - Humanizer.Humanize("WhenIUseAnInputAHere").ShouldBe("When I use an input a here"); - } - - [Fact] - public void WhenInputStringStartsWithANumber_ThenNumberIsDealtWithLikeAWord() - { - Humanizer.Humanize("10NumberIsInTheBegining").ShouldBe("10 number is in the begining"); - } - - [Fact] - public void WhenInputStringEndWithANumber_ThenNumberIsDealtWithLikeAWord() - { - Humanizer.Humanize("NumberIsAtTheEnd100").ShouldBe("Number is at the end 100"); - } - - [Fact] - public void UnderscoredInputStringIsTurnedIntoSentence() - { - Humanizer.Humanize("Underscored_input_string_is_turned_into_sentence") - .ShouldBe("Underscored input string is turned into sentence"); - } - - [Fact] - public void UnderscoredInputStringPreservesCasing() - { - Humanizer.Humanize("Underscored_input_String_is_turned_INTO_sentence") - .ShouldBe("Underscored input String is turned INTO sentence"); - } - - [Fact] - public void OneLetterWordInTheBeginningOfStringIsTurnedIntoAWord() - { - Humanizer.Humanize("XIsFirstPlayer").ShouldBe("X is first player"); - } - - [Theory] - [InlineData("GivenThereAre__start__Cucumbers", "Given there are cucumbers")] - [InlineData("Given_there_are__start__cucumbers", "Given there are cucumbers")] - [InlineData("GivenThereAre__count1__Cucumbers", "Given there are cucumbers")] - [InlineData("Given_there_are__count2__cucumbers", "Given there are cucumbers")] // The spacing rules for numbers are not consequential - [InlineData("GivenMethodTaking__ExampleInt__", "Given method taking ")] - [InlineData("Given_method_taking__ExampleInt__", "Given method taking ")] - [InlineData("__starting__with_example", " with example")] - [InlineData("__starting__WithExample", " with example")] - [InlineData("WhenMethod__takes____two__parameters", "When method parameters")] - [InlineData("When_method__takes____two__parameters", "When method parameters")] - [InlineData("When_method_takes__one__and__two__parameters", "When method takes and parameters")] - [InlineData("WhenMethodTakes__one__and__two__parameters", "When method takes and parameters")] - public void CanDealWithExampleStepNames(string stepName, string expectedStepTitle) - { - Humanizer.Humanize(stepName).ShouldBe(expectedStepTitle); - } - - [Theory] - [InlineData("GivenThereAre__två__Cucumbers", "Given there are cucumbers")] - public void ReportsIllegalExampleStepNames(string stepName, string expectedStepTitle) { - var exception = Record.Exception(() => { - Humanizer.Humanize(stepName).ShouldBe(expectedStepTitle); - }); - - exception.ShouldNotBeNull(); - exception.ShouldBeOfType(); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Disposer/DisposingScenarios.cs b/src/TestStack.BDDfy.Tests/Disposer/DisposingScenarios.cs deleted file mode 100644 index a47ad897..00000000 --- a/src/TestStack.BDDfy.Tests/Disposer/DisposingScenarios.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System; -using System.Linq; -using Shouldly; -using TestStack.BDDfy.Tests.Exceptions; -using Xunit; -using Xunit.Extensions; - -namespace TestStack.BDDfy.Tests.Disposer -{ - public class DisposingScenarios - { - class DisposableScenario(ThrowingMethods throwingMethods): IDisposable - { - private readonly bool _givenThrows = (throwingMethods & ThrowingMethods.Given) > 0; - private readonly bool _whenThrows = (throwingMethods & ThrowingMethods.When) > 0; - private readonly bool _thenThrows = (throwingMethods & ThrowingMethods.Then) > 0; - - public void Given() - { - if (_givenThrows) - throw new Exception(); - } - - public void When() - { - if (_whenThrows) - throw new Exception(); - } - - public void Then() - { - if (_thenThrows) - throw new Exception(); - } - - public void Dispose() { Disposed = true; } - - public bool Disposed { get; set; } - } - - [Theory] - [InlineData(ThrowingMethods.None)] - [InlineData(ThrowingMethods.Given)] - [InlineData(ThrowingMethods.When)] - [InlineData(ThrowingMethods.Then)] - [InlineData(ThrowingMethods.Given | ThrowingMethods.When | ThrowingMethods.Then)] - public void Execute(ThrowingMethods throwingMethods) - { - var scenario = new DisposableScenario(throwingMethods); - - var bddifier = scenario.LazyBDDfy(); - try - { - // we need TestObject for this test; so I disable StoryCache processor for this one test - BDDfy.Configuration.Configurator.Processors.StoryCache.Disable(); - bddifier.Run(); - } - catch (Exception) - { - // there will be an exception but we do not care about it - } - finally - { - BDDfy.Configuration.Configurator.Processors.StoryCache.Enable(); - } - var story = bddifier.Story; - - story.Scenarios.All(s => ((DisposableScenario)s.TestObject).Disposed).ShouldBe(false); - scenario.Disposed.ShouldBe(false); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Exceptions/ExceptionThrowingTest.cs b/src/TestStack.BDDfy.Tests/Exceptions/ExceptionThrowingTest.cs deleted file mode 100644 index 1ca455cd..00000000 --- a/src/TestStack.BDDfy.Tests/Exceptions/ExceptionThrowingTest.cs +++ /dev/null @@ -1,165 +0,0 @@ -using System; -using System.Linq; -using Shouldly; - -namespace TestStack.BDDfy.Tests.Exceptions -{ - public class ExceptionThrowingTest where T : Exception, new() - { - private bool _givenShouldThrow; - private bool _whenShouldThrow; - private bool _thenShouldThrow; - Scenario _scenario; - - void Given() - { - if (_givenShouldThrow) - throw new T(); - } - - void When() - { - if(_whenShouldThrow) - throw new T(); - } - - void Then() - { - if (_thenShouldThrow) - throw new T(); - } - - void TearDown() - { - } - - public void Execute(ThrowingMethods methodToThrow, bool useFluentScanner) - { - SetThrowingStep(methodToThrow); - - Engine engine = useFluentScanner ? FluentScannerBddifier() : ReflectingScannersBddifier(); - - try - { - engine.Run(); - } - finally - { - Story = engine.Story; - _scenario = engine.Story.Scenarios.First(); - } - } - - private Engine FluentScannerBddifier() - { - return this.Given(s => s.Given()) - .When(s => s.When()) - .Then(s => s.Then()) - .TearDownWith(s => s.TearDown()) - .LazyBDDfy(); - } - - private Engine ReflectingScannersBddifier() - { - return this.LazyBDDfy(); - } - - private void SetThrowingStep(ThrowingMethods methodToThrow) - { - _givenShouldThrow = false; - _whenShouldThrow = false; - _thenShouldThrow = false; - - switch (methodToThrow) - { - case ThrowingMethods.Given: - _givenShouldThrow = true; - break; - - case ThrowingMethods.When: - _whenShouldThrow = true; - break; - - case ThrowingMethods.Then: - _thenShouldThrow = true; - break; - } - } - - private Step GetStep(string stepTitle) - { - return _scenario.Steps.First(s => s.Title == stepTitle); - } - - Step GivenStep - { - get - { - return GetStep("Given"); - } - } - - Step WhenStep - { - get { - return GetStep("When"); - } - } - - Step ThenStep - { - get - { - return GetStep("Then"); - } - } - - Step TearDownStep - { - get - { - return GetStep("Tear down"); - } - } - - Scenario Scenario - { - get - { - return _scenario; - } - } - - Story Story { get; set; } - - public void AssertTearDownMethodIsExecuted() - { - TearDownStep.Result.ShouldBe(Result.Passed); - } - - public void AssertGivenStepResult(Result result) - { - GivenStep.Result.ShouldBe(result); - } - - public void AssertWhenStepResult(Result result) - { - WhenStep.Result.ShouldBe(result); - } - - public void AssertThenStepResult(Result result) - { - ThenStep.Result.ShouldBe(result); - } - - public void AssertScenarioResult(Result result) - { - Scenario.Result.ShouldBe(result); - } - - public void AssertStoryResult(Result result) - { - Story.Result.ShouldBe(result); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Exceptions/ExceptionsWhenUsingExamples.cs b/src/TestStack.BDDfy.Tests/Exceptions/ExceptionsWhenUsingExamples.cs deleted file mode 100644 index 5bc1fb53..00000000 --- a/src/TestStack.BDDfy.Tests/Exceptions/ExceptionsWhenUsingExamples.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Tests.Exceptions -{ - public class ExceptionsWhenUsingExamples - { - [Fact] - public void CorrectlyReportsErrorWhenAllStepsNotRun() - { - Should.Throw(() => - { - var exampleTable = new ExampleTable("Arg1", "Arg2") - { - {"foo", "bar"}, - {"foo", "bar"} - }; - - string arg1 = null; - string arg2 = null; - var arg3 = default(string); - this.Given(_ => AFailingStep(arg1), "Given a failing step") - .Then(_ => NonExecutedStep(arg2), "Then multiple assertions") - .And(_ => NonExecutedStep(arg3), "The second one blows up") - .WithExamples(exampleTable) - .BDDfy(); - }); - } - - private void NonExecutedStep(string s) - { - - } - - private void AFailingStep(string s) - { - throw new InvalidOperationException(); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Exceptions/NotImplementedException/NotImplementedExceptionBase.cs b/src/TestStack.BDDfy.Tests/Exceptions/NotImplementedException/NotImplementedExceptionBase.cs deleted file mode 100644 index 4bd38337..00000000 --- a/src/TestStack.BDDfy.Tests/Exceptions/NotImplementedException/NotImplementedExceptionBase.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace TestStack.BDDfy.Tests.Exceptions.NotImplementedException -{ - public class NotImplementedExceptionBase - { - protected readonly ExceptionThrowingTest Sut; - - public NotImplementedExceptionBase() - { - Sut = new ExceptionThrowingTest(); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Exceptions/NotImplementedException/WhenGivenThrowsNotImplementedException.cs b/src/TestStack.BDDfy.Tests/Exceptions/NotImplementedException/WhenGivenThrowsNotImplementedException.cs deleted file mode 100644 index 27240924..00000000 --- a/src/TestStack.BDDfy.Tests/Exceptions/NotImplementedException/WhenGivenThrowsNotImplementedException.cs +++ /dev/null @@ -1,105 +0,0 @@ -using System; -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Tests.Exceptions.NotImplementedException -{ - public class WhenGivenThrowsNotImplementedException : NotImplementedExceptionBase - { - private void ExecuteUsingFluentScanner() - { - var ex = Should.Throw(() => Sut.Execute(ThrowingMethods.Given, true)); - ex.GetType().FullName.ShouldContain("Inconclusive"); - } - - private void ExecuteUsingReflectingScanners() - { - var ex = Should.Throw(() => Sut.Execute(ThrowingMethods.Given, false)); - ex.GetType().FullName.ShouldContain("Inconclusive"); - } - - [Fact] - public void GivenIsReportedAsNotImplementedWhenUsingReflectingScanners() - { - ExecuteUsingReflectingScanners(); - Sut.AssertGivenStepResult(Result.NotImplemented); - } - - [Fact] - public void GivenIsReportedAsNotImplementedWhenUsingFluentScanners() - { - ExecuteUsingFluentScanner(); - Sut.AssertGivenStepResult(Result.NotImplemented); - } - - [Fact] - public void WhenIsNotExecutedWhenUsingReflectingScanners() - { - ExecuteUsingReflectingScanners(); - Sut.AssertWhenStepResult(Result.NotExecuted); - } - - [Fact] - public void WhenIsNotExecutedWhenUsingFluentScanners() - { - ExecuteUsingFluentScanner(); - Sut.AssertWhenStepResult(Result.NotExecuted); - } - - [Fact] - public void ThenIsNotExecutedWhenUsingReflectingScanner() - { - ExecuteUsingReflectingScanners(); - Sut.AssertThenStepResult(Result.NotExecuted); - } - - [Fact] - public void ThenIsNotExecutedWhenUsingFluentScanner() - { - ExecuteUsingFluentScanner(); - Sut.AssertThenStepResult(Result.NotExecuted); - } - - [Fact] - public void ScenarioResultReturnsNotImplementedWhenUsingReflectingScanners() - { - ExecuteUsingReflectingScanners(); - Sut.AssertScenarioResult(Result.NotImplemented); - } - - [Fact] - public void ScenarioResultReturnsNotImplementedWhenUsingFluentScanner() - { - ExecuteUsingFluentScanner(); - Sut.AssertScenarioResult(Result.NotImplemented); - } - - [Fact] - public void StoryResultReturnsNotImplementedWhenUsingReflectingScanners() - { - ExecuteUsingReflectingScanners(); - Sut.AssertStoryResult(Result.NotImplemented); - } - - [Fact] - public void StoryResultReturnsNotImplementedWhenUsingFluentScanner() - { - ExecuteUsingFluentScanner(); - Sut.AssertStoryResult(Result.NotImplemented); - } - - [Fact] - public void TearDownMethodIsExecutedWhenUsingReflectingScanners() - { - ExecuteUsingReflectingScanners(); - Sut.AssertTearDownMethodIsExecuted(); - } - - [Fact] - public void TearDownMethodIsExecutedWhenUsingFluentScanner() - { - ExecuteUsingFluentScanner(); - Sut.AssertTearDownMethodIsExecuted(); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Exceptions/NotImplementedException/WhenThenThrowsNotImplementedException.cs b/src/TestStack.BDDfy.Tests/Exceptions/NotImplementedException/WhenThenThrowsNotImplementedException.cs deleted file mode 100644 index 1f00d20e..00000000 --- a/src/TestStack.BDDfy.Tests/Exceptions/NotImplementedException/WhenThenThrowsNotImplementedException.cs +++ /dev/null @@ -1,105 +0,0 @@ -using System; -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Tests.Exceptions.NotImplementedException -{ - public class WhenThenThrowsNotImplementedException : NotImplementedExceptionBase - { - private void ExecuteUsingReflectingScanners() - { - var ex = Should.Throw(() => Sut.Execute(ThrowingMethods.Then, false)); - ex.GetType().FullName.ShouldContain("Inconclusive"); - } - - private void ExecuteUsingFluentScanner() - { - var ex = Should.Throw(() => Sut.Execute(ThrowingMethods.Then, true)); - ex.GetType().FullName.ShouldContain("Inconclusive"); - } - - [Fact] - public void GivenIsReportedAsSuccessfulWhenUsingReflectingScanners() - { - ExecuteUsingReflectingScanners(); - Sut.AssertGivenStepResult(Result.Passed); - } - - [Fact] - public void WhenIsReportedAsSuccessfulWhenUsingReflectingScanners() - { - ExecuteUsingReflectingScanners(); - Sut.AssertWhenStepResult(Result.Passed); - } - - [Fact] - public void ThenIsReportedAsNotImplemenetedWhenUsingReflectingScanners() - { - ExecuteUsingReflectingScanners(); - Sut.AssertThenStepResult(Result.NotImplemented); - } - - [Fact] - public void ScenarioResultReturnsNoImplementedWhenUsingReflectingScanners() - { - ExecuteUsingReflectingScanners(); - Sut.AssertScenarioResult(Result.NotImplemented); - } - - [Fact] - public void StoryResultReturnsNoImplementedWhenUsingReflectingScanners() - { - ExecuteUsingReflectingScanners(); - Sut.AssertStoryResult(Result.NotImplemented); - } - - [Fact] - public void TearDownMethodIsExecutedWhenUsingReflectingScanners() - { - ExecuteUsingReflectingScanners(); - Sut.AssertTearDownMethodIsExecuted(); - } - - [Fact] - public void GivenIsReportedAsSuccessfulWhenUsingFluentScanner() - { - ExecuteUsingFluentScanner(); - Sut.AssertGivenStepResult(Result.Passed); - } - - [Fact] - public void WhenIsReportedAsSuccessfulWhenUsingFluentScanner() - { - ExecuteUsingFluentScanner(); - Sut.AssertWhenStepResult(Result.Passed); - } - - [Fact] - public void ThenIsReportedAsNotImplemenetedWhenUsingFluentScanner() - { - ExecuteUsingFluentScanner(); - Sut.AssertThenStepResult(Result.NotImplemented); - } - - [Fact] - public void ScenarioResultReturnsNoImplementedWhenUsingFluentScanner() - { - ExecuteUsingFluentScanner(); - Sut.AssertScenarioResult(Result.NotImplemented); - } - - [Fact] - public void StoryResultReturnsNoImplementedWhenUsingFluentScanner() - { - ExecuteUsingFluentScanner(); - Sut.AssertStoryResult(Result.NotImplemented); - } - - [Fact] - public void TearDownMethodIsExecutedWhenUsingFluentScanner() - { - ExecuteUsingFluentScanner(); - Sut.AssertTearDownMethodIsExecuted(); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Exceptions/NotImplementedException/WhenWhenThrowsNotImplementedException.cs b/src/TestStack.BDDfy.Tests/Exceptions/NotImplementedException/WhenWhenThrowsNotImplementedException.cs deleted file mode 100644 index 1788f865..00000000 --- a/src/TestStack.BDDfy.Tests/Exceptions/NotImplementedException/WhenWhenThrowsNotImplementedException.cs +++ /dev/null @@ -1,105 +0,0 @@ -using System; -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Tests.Exceptions.NotImplementedException -{ - public class WhenWhenThrowsNotImplementedException : NotImplementedExceptionBase - { - private void ExecuteUsingReflectingScanners() - { - var ex = Should.Throw(() => Sut.Execute(ThrowingMethods.When, false)); - ex.GetType().FullName.ShouldContain("Inconclusive"); - } - - private void ExecuteUsingFluentScanner() - { - var ex = Should.Throw(() => Sut.Execute(ThrowingMethods.When, true)); - ex.GetType().FullName.ShouldContain("Inconclusive"); - } - - [Fact] - public void GivenIsReportedAsSuccessfulWhenUsingReflectingScanners() - { - ExecuteUsingReflectingScanners(); - Sut.AssertGivenStepResult(Result.Passed); - } - - [Fact] - public void WhenIsReportedAsNotImplementedWhenUsingReflectingScanners() - { - ExecuteUsingReflectingScanners(); - Sut.AssertWhenStepResult(Result.NotImplemented); - } - - [Fact] - public void ThenIsNotExecutedWhenUsingReflectingScanners() - { - ExecuteUsingReflectingScanners(); - Sut.AssertThenStepResult(Result.NotExecuted); - } - - [Fact] - public void ScenarioResultReturnsNotImplementedWhenUsingReflectingScanners() - { - ExecuteUsingReflectingScanners(); - Sut.AssertScenarioResult(Result.NotImplemented); - } - - [Fact] - public void StoryResultReturnsNotImplementedWhenUsingReflectingScanners() - { - ExecuteUsingReflectingScanners(); - Sut.AssertStoryResult(Result.NotImplemented); - } - - [Fact] - public void TearDownMethodIsExecutedWhenUsingReflectingScanners() - { - ExecuteUsingReflectingScanners(); - Sut.AssertTearDownMethodIsExecuted(); - } - - [Fact] - public void GivenIsReportedAsSuccessfulWhenUsingFluentScanner() - { - ExecuteUsingFluentScanner(); - Sut.AssertGivenStepResult(Result.Passed); - } - - [Fact] - public void WhenIsReportedAsNotImplementedWhenUsingFluentScanner() - { - ExecuteUsingFluentScanner(); - Sut.AssertWhenStepResult(Result.NotImplemented); - } - - [Fact] - public void ThenIsNotExecutedWhenUsingFluentScanner() - { - ExecuteUsingFluentScanner(); - Sut.AssertThenStepResult(Result.NotExecuted); - } - - [Fact] - public void ScenarioResultReturnsNotImplementedWhenUsingFluentScanner() - { - ExecuteUsingFluentScanner(); - Sut.AssertScenarioResult(Result.NotImplemented); - } - - [Fact] - public void StoryResultReturnsNotImplementedWhenUsingFluentScanner() - { - ExecuteUsingFluentScanner(); - Sut.AssertStoryResult(Result.NotImplemented); - } - - [Fact] - public void TearDownMethodIsExecutedWhenUsingFluentScanner() - { - ExecuteUsingFluentScanner(); - Sut.AssertTearDownMethodIsExecuted(); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Exceptions/OtherExceptions/OtherExceptionBase.cs b/src/TestStack.BDDfy.Tests/Exceptions/OtherExceptions/OtherExceptionBase.cs deleted file mode 100644 index ffc4a4c1..00000000 --- a/src/TestStack.BDDfy.Tests/Exceptions/OtherExceptions/OtherExceptionBase.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; - -namespace TestStack.BDDfy.Tests.Exceptions.OtherExceptions -{ - public class OtherExceptionBase - { - protected readonly ExceptionThrowingTest Sut; - - public OtherExceptionBase() - { - Sut = new ExceptionThrowingTest(); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Exceptions/OtherExceptions/WhenGivenThrowsException.cs b/src/TestStack.BDDfy.Tests/Exceptions/OtherExceptions/WhenGivenThrowsException.cs deleted file mode 100644 index e34a5203..00000000 --- a/src/TestStack.BDDfy.Tests/Exceptions/OtherExceptions/WhenGivenThrowsException.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System; -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Tests.Exceptions.OtherExceptions -{ - public class WhenGivenThrowsException : OtherExceptionBase - { - private void ExecuteUsingReflectingScanners() - { - Should.Throw(() => Sut.Execute(ThrowingMethods.Given, false)); - } - - private void ExecuteUsingFluentScanners() - { - Should.Throw(() => Sut.Execute(ThrowingMethods.Given, true)); - } - - [Fact] - public void GivenShouldBeReportedAsFailedWhenUsingReflectingScanners() - { - ExecuteUsingReflectingScanners(); - Sut.AssertGivenStepResult(Result.Failed); - } - - [Fact] - public void WhenShouldNotBeExecutedWhenUsingReflectingScanners() - { - ExecuteUsingReflectingScanners(); - Sut.AssertWhenStepResult(Result.NotExecuted); - } - - [Fact] - public void ThenShouldNotBeExecutedWhenUsingReflectingScanners() - { - ExecuteUsingReflectingScanners(); - Sut.AssertThenStepResult(Result.NotExecuted); - } - - [Fact] - public void ScenarioResultReturnsFailedWhenUsingReflectingScanners() - { - ExecuteUsingReflectingScanners(); - Sut.AssertScenarioResult(Result.Failed); - } - - [Fact] - public void StoryResultReturnsFailedWhenUsingReflectingScanners() - { - ExecuteUsingReflectingScanners(); - Sut.AssertStoryResult(Result.Failed); - } - - [Fact] - public void TearDownMethodIsExecutedWhenUsingReflectingScanners() - { - ExecuteUsingReflectingScanners(); - Sut.AssertTearDownMethodIsExecuted(); - } - - [Fact] - public void GivenShouldBeReportedAsFailedWhenUsingFluentScanners() - { - ExecuteUsingFluentScanners(); - Sut.AssertGivenStepResult(Result.Failed); - } - - [Fact] - public void WhenShouldNotBeExecutedWhenUsingFluentScanners() - { - ExecuteUsingFluentScanners(); - Sut.AssertWhenStepResult(Result.NotExecuted); - } - - [Fact] - public void ThenShouldNotBeExecutedWhenUsingFluentScanners() - { - ExecuteUsingFluentScanners(); - Sut.AssertThenStepResult(Result.NotExecuted); - } - - [Fact] - public void ScenarioResultReturnsFailedWhenUsingFluentScanners() - { - ExecuteUsingFluentScanners(); - Sut.AssertScenarioResult(Result.Failed); - } - - [Fact] - public void StoryResultReturnsFailedWhenUsingFluentScanners() - { - ExecuteUsingFluentScanners(); - Sut.AssertStoryResult(Result.Failed); - } - - [Fact] - public void TearDownMethodIsExecutedWhenUsingFluentScanners() - { - ExecuteUsingFluentScanners(); - Sut.AssertTearDownMethodIsExecuted(); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Exceptions/OtherExceptions/WhenResolvingExceptionsFromDifferentScanners.cs b/src/TestStack.BDDfy.Tests/Exceptions/OtherExceptions/WhenResolvingExceptionsFromDifferentScanners.cs deleted file mode 100644 index 7c59bdc8..00000000 --- a/src/TestStack.BDDfy.Tests/Exceptions/OtherExceptions/WhenResolvingExceptionsFromDifferentScanners.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.Xml; -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Tests.Exceptions.OtherExceptions -{ - public class WhenResolvingExceptionsFromDifferentScanners - { - private ExceptionThrowingTest _sut; - - /// - /// Test to resolve issue where fluent scanner was returning the inner exception rather than the outer one. - /// Issue 17: https://github.com/TestStack/TestStack.BDDfy/issues/17 - /// - [Fact] - public void FluentScannerShouldReturnOriginalExceptionAndNotInnerException() - { - _sut = new ExceptionThrowingTest(); - Should.Throw(() => _sut.Execute(ThrowingMethods.Given, true)); - } - - [Fact] - public void ReflectiveScannerShouldReturnOriginalExceptionAndNotTargetInvocationException() - { - _sut = new ExceptionThrowingTest(); - Should.Throw(() => _sut.Execute(ThrowingMethods.Given, false)); - } - - private class OuterException : Exception - { - public OuterException() - : base("outer", new XmlException("inner exception")) - { - } - } - } -} diff --git a/src/TestStack.BDDfy.Tests/Exceptions/OtherExceptions/WhenThenThrowsException.cs b/src/TestStack.BDDfy.Tests/Exceptions/OtherExceptions/WhenThenThrowsException.cs deleted file mode 100644 index c1eab33d..00000000 --- a/src/TestStack.BDDfy.Tests/Exceptions/OtherExceptions/WhenThenThrowsException.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System; -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Tests.Exceptions.OtherExceptions -{ - public class WhenThenThrowsException : OtherExceptionBase - { - private void ExecuteUsingReflectingScanners() - { - Should.Throw(() => Sut.Execute(ThrowingMethods.Then, false)); - } - - private void ExecuteUsingFluentScanner() - { - Should.Throw(() => Sut.Execute(ThrowingMethods.Then, true)); - } - - [Fact] - public void GivenIsReportedAsSuccessfulWhenUsingReflectingScanners() - { - ExecuteUsingReflectingScanners(); - Sut.AssertGivenStepResult(Result.Passed); - } - - [Fact] - public void WhenIsReportedAsSuccessfulWhenUsingReflectingScanners() - { - ExecuteUsingReflectingScanners(); - Sut.AssertWhenStepResult(Result.Passed); - } - - [Fact] - public void ThenIsReportedAsFailedWhenUsingReflectingScanners() - { - ExecuteUsingReflectingScanners(); - Sut.AssertThenStepResult(Result.Failed); - } - - [Fact] - public void ScenarioResultReturnsFailedWhenUsingReflectingScanners() - { - ExecuteUsingReflectingScanners(); - Sut.AssertScenarioResult(Result.Failed); - } - - [Fact] - public void StoryResultReturnsFailedWhenUsingReflectingScanners() - { - ExecuteUsingReflectingScanners(); - Sut.AssertStoryResult(Result.Failed); - } - - [Fact] - public void TearDownMethodIsExecutedWhenUsingReflectingScanners() - { - ExecuteUsingReflectingScanners(); - Sut.AssertTearDownMethodIsExecuted(); - } - - [Fact] - public void GivenIsReportedAsSuccessfulWhenUsingFluentScanners() - { - ExecuteUsingFluentScanner(); - Sut.AssertGivenStepResult(Result.Passed); - } - - [Fact] - public void WhenIsReportedAsSuccessfulWhenUsingFluentScanners() - { - ExecuteUsingFluentScanner(); - Sut.AssertWhenStepResult(Result.Passed); - } - - [Fact] - public void ThenIsReportedAsFailedWhenUsingFluentScanners() - { - ExecuteUsingFluentScanner(); - Sut.AssertThenStepResult(Result.Failed); - } - - [Fact] - public void ScenarioResultReturnsFailedWhenUsingFluentScanners() - { - ExecuteUsingFluentScanner(); - Sut.AssertScenarioResult(Result.Failed); - } - - [Fact] - public void StoryResultReturnsFailedWhenUsingFluentScanners() - { - ExecuteUsingFluentScanner(); - Sut.AssertStoryResult(Result.Failed); - } - - [Fact] - public void TearDownMethodIsExecutedWhenUsingFluentScanners() - { - ExecuteUsingFluentScanner(); - Sut.AssertTearDownMethodIsExecuted(); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Exceptions/OtherExceptions/WhenWhenThrowsException.cs b/src/TestStack.BDDfy.Tests/Exceptions/OtherExceptions/WhenWhenThrowsException.cs deleted file mode 100644 index 11741e33..00000000 --- a/src/TestStack.BDDfy.Tests/Exceptions/OtherExceptions/WhenWhenThrowsException.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System; -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Tests.Exceptions.OtherExceptions -{ - public class WhenWhenThrowsException : OtherExceptionBase - { - private void ExecuteUsingFluentScanner() - { - Should.Throw(() => Sut.Execute(ThrowingMethods.When, true)); - } - - private void ExecuteUsingReflectingScanners() - { - Should.Throw(() => Sut.Execute(ThrowingMethods.When, false)); - } - - [Fact] - public void GivenIsReportedAsSuccessfulWhenUsingReflectingScanners() - { - ExecuteUsingReflectingScanners(); - Sut.AssertGivenStepResult(Result.Passed); - } - - [Fact] - public void GivenIsReportedAsSuccessfulWhenUsingFluentScanner() - { - ExecuteUsingFluentScanner(); - Sut.AssertGivenStepResult(Result.Passed); - } - - [Fact] - public void WhenIsReportedAsFailedWhenUsingReflectingScanners() - { - ExecuteUsingReflectingScanners(); - Sut.AssertWhenStepResult(Result.Failed); - } - - [Fact] - public void WhenIsReportedAsFailedWhenUsingFluentScanner() - { - ExecuteUsingFluentScanner(); - Sut.AssertWhenStepResult(Result.Failed); - } - - [Fact] - public void ThenIsNotExecutedWhenUsingReflectingScanners() - { - ExecuteUsingReflectingScanners(); - Sut.AssertThenStepResult(Result.NotExecuted); - } - - [Fact] - public void ThenIsNotExecutedWhenUsingFluentScanner() - { - ExecuteUsingFluentScanner(); - Sut.AssertThenStepResult(Result.NotExecuted); - } - - [Fact] - public void ScenarioResultReturnsFailedWhenUsingReflectingScanners() - { - ExecuteUsingReflectingScanners(); - Sut.AssertScenarioResult(Result.Failed); - } - - [Fact] - public void ScenarioResultReturnsFailedWhenUsingFluentScanner() - { - ExecuteUsingFluentScanner(); - Sut.AssertScenarioResult(Result.Failed); - } - - [Fact] - public void StoryResultReturnsFailedWhenUsingReflectingScanners() - { - ExecuteUsingReflectingScanners(); - Sut.AssertStoryResult(Result.Failed); - } - - [Fact] - public void StoryResultReturnsFailedWhenUsingFluentScanner() - { - ExecuteUsingFluentScanner(); - Sut.AssertStoryResult(Result.Failed); - } - - [Fact] - public void TearDownMethodIsExecutedWhenUsingReflectingScanners() - { - ExecuteUsingReflectingScanners(); - Sut.AssertTearDownMethodIsExecuted(); - } - - [Fact] - public void TearDownMethodIsExecutedWhenUsingFluentScanner() - { - ExecuteUsingFluentScanner(); - Sut.AssertTearDownMethodIsExecuted(); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Exceptions/ThrowingMethods.cs b/src/TestStack.BDDfy.Tests/Exceptions/ThrowingMethods.cs deleted file mode 100644 index 5a09e2f7..00000000 --- a/src/TestStack.BDDfy.Tests/Exceptions/ThrowingMethods.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; - -namespace TestStack.BDDfy.Tests.Exceptions -{ - [Flags] - public enum ThrowingMethods - { - None = 0, - Given = 1, - When = 2, - Then = 4 - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Exceptions/WhenAnInconclusiveTestIsRun.cs b/src/TestStack.BDDfy.Tests/Exceptions/WhenAnInconclusiveTestIsRun.cs deleted file mode 100644 index 67a2e548..00000000 --- a/src/TestStack.BDDfy.Tests/Exceptions/WhenAnInconclusiveTestIsRun.cs +++ /dev/null @@ -1,121 +0,0 @@ -using System.Linq; -using Shouldly; -using TestStack.BDDfy.Processors; -using Xunit; - -namespace TestStack.BDDfy.Tests.Exceptions -{ - public class WhenAnInconclusiveTestIsRun - { - public class InconclusiveTestClass - { - public void GivenAClassUnderTest() - { - } - - public void WhenInconclusiveExceptionIsThrownInOneOfTheMethods() - { - } - - public void ThenTheContextIsFlaggedAsInconclusive() - { - throw new InconclusiveException(); - } - - public void TearDownThis() - { - - } - } - - Engine _engine; - private Scenario _scenario; - - Step GivenStep - { - get - { - return _scenario.Steps.Single(s => s.Title == "Given a class under test"); - } - } - - Step WhenStep - { - get - { - return _scenario.Steps.Single(s => s.Title == "When inconclusive exception is thrown in one of the methods"); - } - } - - Step ThenStep - { - get - { - return _scenario.Steps.Single(s => s.Title == "Then the context is flagged as inconclusive"); - } - } - - Step DisposeStep - { - get - { - return _scenario.Steps.Single(s => s.Title == "Tear down this"); - } - } - - public WhenAnInconclusiveTestIsRun() - { - _engine = new InconclusiveTestClass().LazyBDDfy(); - Should.Throw(() => _engine.Run()); - _scenario = _engine.Story.Scenarios.First(); - } - - [Fact] - public void ResultIsInconclusive() - { - _scenario.Result.ShouldBe(Result.Inconclusive); - } - - [Fact] - public void ThenIsFlaggedAsInconclusive() - { - ThenStep.Result.ShouldBe(Result.Inconclusive); - } - - [Fact] - public void ThenHasAnInconclusiveExceptionOnIt() - { - ThenStep.Exception.ShouldBeAssignableTo(); - } - - [Fact] - public void GivenIsFlaggedAsSuccessful() - { - GivenStep.Result.ShouldBe(Result.Passed); - } - - [Fact] - public void WhenIsFlaggedAsSuccessful() - { - WhenStep.Result.ShouldBe(Result.Passed); - } - - [Fact] - public void ScenarioResultReturnsInconclusive() - { - _scenario.Result.ShouldBe(Result.Inconclusive); - } - - [Fact] - public void StoryResultReturnsInconclusive() - { - _scenario.Result.ShouldBe(Result.Inconclusive); - } - - [Fact] - public void TearDownMethodIsExecuted() - { - DisposeStep.Result.ShouldBe(Result.Passed); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/ExclusiveAccessToConfiguratorFixture.cs b/src/TestStack.BDDfy.Tests/ExclusiveAccessToConfiguratorFixture.cs deleted file mode 100644 index 2c9f5f33..00000000 --- a/src/TestStack.BDDfy.Tests/ExclusiveAccessToConfiguratorFixture.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Xunit; - -namespace TestStack.BDDfy.Tests -{ - [CollectionDefinition("ExclusiveAccessToConfigurator", DisableParallelization = true)] - public class ExclusiveAccessToConfiguratorFixture - { - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Helpers.cs b/src/TestStack.BDDfy.Tests/Helpers.cs deleted file mode 100644 index 162bde49..00000000 --- a/src/TestStack.BDDfy.Tests/Helpers.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Linq.Expressions; -using System.Reflection; - -namespace TestStack.BDDfy.Tests -{ - public class Helpers - { - public static MethodInfo GetMethodInfo(Expression methodOn) - { - var methodCallExp = (MethodCallExpression)methodOn.Body; - return methodCallExp.Method; - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Processors/TestRunnerTests.cs b/src/TestStack.BDDfy.Tests/Processors/TestRunnerTests.cs deleted file mode 100644 index 85b32b7f..00000000 --- a/src/TestStack.BDDfy.Tests/Processors/TestRunnerTests.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Shouldly; -using TestStack.BDDfy.Processors; -using Xunit; - -namespace TestStack.BDDfy.Tests.Processors -{ - public class TestRunnerTests - { - public int ExampleValue { get; set; } - - [Fact] - public void InitializesScenarioWithExampleBeforeRunning() - { - const int expectedValue = 1; - var actualValue = 0; - var exampleTable = new ExampleTable("ExampleValue") - { - expectedValue - }.Single(); - - var sut = new TestRunner(); - Func action = o => actualValue = ExampleValue; - var steps = new List { new(action, new StepTitle("A Step"), true, ExecutionOrder.Initialize, true, new List()) }; - - var scenarioWithExample = new Scenario("id", this, steps, "Scenario Text", exampleTable, new List()); - var story = new Story(new StoryMetadata(typeof(TestRunnerTests), new StoryNarrativeAttribute()), scenarioWithExample); - - sut.Process(story); - - actualValue.ShouldBe(expectedValue); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Reporters/Diagnostics/DiagnosticsReportBuilderTests.cs b/src/TestStack.BDDfy.Tests/Reporters/Diagnostics/DiagnosticsReportBuilderTests.cs deleted file mode 100644 index d5165da4..00000000 --- a/src/TestStack.BDDfy.Tests/Reporters/Diagnostics/DiagnosticsReportBuilderTests.cs +++ /dev/null @@ -1,24 +0,0 @@ -using NSubstitute; -using TestStack.BDDfy.Reporters; -using TestStack.BDDfy.Reporters.Diagnostics; -using TestStack.BDDfy.Reporters.Serializers; -using Xunit; - -namespace TestStack.BDDfy.Tests.Reporters.Diagnostics -{ - public class DiagnosticsReportBuilderTests - { - [Fact] - public void ShouldSerializeDiagnosticDataToSpecifiedFormat() - { - var serializer = Substitute.For(); - var testData = new ReportTestData().CreateTwoStoriesEachWithOneFailingScenarioAndOnePassingScenarioWithThreeStepsOfFiveMilliseconds(); - var model = new FileReportModel(testData.ToReportModel()); - var sut = new DiagnosticsReportBuilder(serializer); - - sut.CreateReport(model); - - serializer.Received().Serialize(Arg.Any()); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Reporters/Diagnostics/DiagnosticsReporterTests.cs b/src/TestStack.BDDfy.Tests/Reporters/Diagnostics/DiagnosticsReporterTests.cs deleted file mode 100644 index b7fd6c26..00000000 --- a/src/TestStack.BDDfy.Tests/Reporters/Diagnostics/DiagnosticsReporterTests.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Collections.Generic; -using NSubstitute; -using TestStack.BDDfy.Reporters; -using TestStack.BDDfy.Reporters.Diagnostics; -using TestStack.BDDfy.Reporters.Writers; -using Xunit; - -namespace TestStack.BDDfy.Tests.Reporters.Diagnostics -{ - public class DiagnosticsReporterTests - { - private IReportBuilder _builder; - private IReportWriter _writer; - - [Fact] - public void ShouldCreateReportIfProcessingSucceeds() - { - var sut = CreateSut(); - _builder.CreateReport(Arg.Any()).Returns("Report Data"); - - sut.Process(new List()); - - _writer.Received().OutputReport("Report Data", Arg.Any(), Arg.Any()); - } - - [Fact] - public void ShouldPrintErrorInReportIfProcessingFails() - { - var sut = CreateSut(); - _builder.CreateReport(Arg.Any()).Returns(x => { throw new Exception("Error occurred."); }); - - sut.Process(new List()); - - _writer.Received().OutputReport( - Arg.Is(s => s.StartsWith("Error occurred.")), - Arg.Any(), - Arg.Any()); - } - - private DiagnosticsReporter CreateSut() - { - _builder = Substitute.For(); - _writer = Substitute.For(); - return new DiagnosticsReporter(_builder, _writer); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Reporters/Diagnostics/WhenBuildingReportDiagnostics.cs b/src/TestStack.BDDfy.Tests/Reporters/Diagnostics/WhenBuildingReportDiagnostics.cs deleted file mode 100644 index 0f82ef98..00000000 --- a/src/TestStack.BDDfy.Tests/Reporters/Diagnostics/WhenBuildingReportDiagnostics.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Shouldly; -using TestStack.BDDfy.Reporters; -using TestStack.BDDfy.Reporters.Diagnostics; -using Xunit; - -namespace TestStack.BDDfy.Tests.Reporters.Diagnostics -{ - public class WhenBuildingReportDiagnostics - { - private DiagnosticsReportBuilder _sut; - private IEnumerable _stories; - private IList _result; - - internal void GivenADiagnosticsReportBuilder() - { - _sut = new DiagnosticsReportBuilder(); - } - - internal void AndGivenTwoStoriesEachWithTwoScenariosWithThreeStepsOfFiveMilliseconds() - { - _stories = new ReportTestData().CreateTwoStoriesEachWithOneFailingScenarioAndOnePassingScenarioWithThreeStepsOfFiveMilliseconds(); - } - - internal void WhenTheDiagnosticDataIsCalculated() - { - _result = _sut.GetDiagnosticData(new FileReportModel(_stories.ToReportModel())); - } - - internal void ThenTwoStoriesShouldBeReturned() - { - _result.Count.ShouldBe(2); - } - - internal void AndThenEachStoryShouldHaveDurationOf30Milliseconds() - { - _result.ToList().ForEach(story => story.Duration.ShouldBe(30)); - } - - internal void AndThenEachScenarioShouldHaveDurationOf10Milliseconds() - { - _result[0].Scenarios.ForEach(scenario => scenario.Duration.ShouldBe(15)); - _result[1].Scenarios.ForEach(scenario => scenario.Duration.ShouldBe(15)); - } - - internal void AndThenEachStepShouldHaveDurationOf5Milliseconds() - { - _result[0].Scenarios.ForEach(scenario => scenario.Steps.ForEach(step => step.Duration.ShouldBe(5))); - _result[1].Scenarios.ForEach(scenario => scenario.Steps.ForEach(step => step.Duration.ShouldBe(5))); - } - - [Fact] - public void RunSpecs() - { - this.BDDfy(); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Reporters/Html/ClassicReportBuilderTests.ShouldProduceExpectedHtml.approved.txt b/src/TestStack.BDDfy.Tests/Reporters/Html/ClassicReportBuilderTests.ShouldProduceExpectedHtml.approved.txt deleted file mode 100644 index 436429e4..00000000 --- a/src/TestStack.BDDfy.Tests/Reporters/Html/ClassicReportBuilderTests.ShouldProduceExpectedHtml.approved.txt +++ /dev/null @@ -1,174 +0,0 @@ - - - - - - - BDDfy Test Result 25/03/2014 - - -
-
-
BDDfy
-
A simple BDD framework for .Net developers
-
-
-

Summary:

-
    -
  • -
    -
    Stories
    - 2 -
    -
  • -
  • -
    -
    Scenarios
    - 4 -
    -
  • -
  • -
    -
    Passed
    - 3 -
    -
  • -
  • -
    -
    Inconclusive
    - 0 -
    -
  • -
  • -
    -
    Not Implemented
    - 0 -
    -
  • -
  • -
    -
    Failed
    - 1 -
    -
  • -
-
-
-
-

Details:

- -
-
    -
  • -
    - -
    -
    -
    Happy Path Scenario
    -
      -
    • - Given a positive account balance -
    • -
    • - When the account holder requests money -
    • -
    • - Then money is dispensed -
    • -
    -
    -
    -
    Sad Path Scenario
    -
      -
    • - Given a negative account balance -
    • -
    • - When the account holder requests money -
    • -
    • - Then no money is dispensed [Exception Message: 'Boom'] -
      - at TestStack.BDDfy.Tests.Reporters.ReportTestData.GetScenarios(Boolean includeFailingScenario, Boolean includeExamples) in ...\ReportTestData.cs -
      -
    • -
    -
    -
    -
    -
  • -
  • -
    - -
    -
    -
    Happy Path Scenario
    -
      -
    • - Given a positive account balance -
    • -
    • - When the account holder requests money -
    • -
    • - Then money is dispensed -
    • -
    -
    -
    -
    Sad Path Scenario
    -
      -
    • - Given a negative account balance -
    • -
    • - When the account holder requests money -
    • -
    • - Then no money is dispensed -
    • -
    -
    -
    -
    -
  • -
-

Tested at: 25/03/2014 11:30:05

-
-
- - - - - - diff --git a/src/TestStack.BDDfy.Tests/Reporters/Html/ClassicReportBuilderTests.ShouldProduceExpectedHtmlWithExamples.approved.txt b/src/TestStack.BDDfy.Tests/Reporters/Html/ClassicReportBuilderTests.ShouldProduceExpectedHtmlWithExamples.approved.txt deleted file mode 100644 index 5a87b3d6..00000000 --- a/src/TestStack.BDDfy.Tests/Reporters/Html/ClassicReportBuilderTests.ShouldProduceExpectedHtmlWithExamples.approved.txt +++ /dev/null @@ -1,194 +0,0 @@ - - - - - - - BDDfy Test Result 25/03/2014 - - -
-
-
BDDfy
-
A simple BDD framework for .Net developers
-
-
-

Summary:

-
    -
  • -
    -
    Stories
    - 2 -
    -
  • -
  • -
    -
    Scenarios
    - 4 -
    -
  • -
  • -
    -
    Passed
    - 3 -
    -
  • -
  • -
    -
    Inconclusive
    - 0 -
    -
  • -
  • -
    -
    Not Implemented
    - 0 -
    -
  • -
  • -
    -
    Failed
    - 1 -
    -
  • -
-
-
-
-

Details:

- -
-
    -
  • -
    - -
    -
    -
    Example Scenario
    -
      -
    • - Given a <sign> account balance -
    • -
    • - When the account holder requests money -
    • -
    • - Then money <action> dispensed -
    • -
    • - Examples: - - - - - - - - - - - - - - - - - - - -
      signactionError
      positiveis -
      negativeis not - Boom -With -New lines -
      - at TestStack.BDDfy.Tests.Reporters.ReportTestData.GetScenarios(Boolean includeFailingScenario, Boolean includeExamples) in ...\ReportTestData.cs -
      -
      -
    • -
    -
    -
    -
    -
  • -
  • -
    - -
    -
    -
    Example Scenario
    -
      -
    • - Given a <sign> account balance -
    • -
    • - When the account holder requests money -
    • -
    • - Then money <action> dispensed -
    • -
    • - Examples: - - - - - - - - - - - - - - - - -
      signaction
      positiveis
      negativeis not
      -
    • -
    -
    -
    -
    -
  • -
-

Tested at: 25/03/2014 11:30:05

-
-
- - - - - - diff --git a/src/TestStack.BDDfy.Tests/Reporters/Html/ClassicReportBuilderTests.cs b/src/TestStack.BDDfy.Tests/Reporters/Html/ClassicReportBuilderTests.cs deleted file mode 100644 index 6ea5dd5d..00000000 --- a/src/TestStack.BDDfy.Tests/Reporters/Html/ClassicReportBuilderTests.cs +++ /dev/null @@ -1,42 +0,0 @@ -#if Approvals -using System; -using System.Runtime.CompilerServices; -using TestStack.BDDfy.Reporters; -using TestStack.BDDfy.Reporters.Html; -using Xunit; - -namespace TestStack.BDDfy.Tests.Reporters.Html -{ - public class ClassicReportBuilderTests - { - [Fact] - [MethodImpl(MethodImplOptions.NoInlining)] - public void ShouldProduceExpectedHtml() - { - var model = - new HtmlReportModel(new ReportTestData().CreateTwoStoriesEachWithOneFailingScenarioAndOnePassingScenarioWithThreeStepsOfFiveMilliseconds() - .ToReportModel()) - { - RunDate = new DateTime(2014, 3, 25, 11, 30, 5) - }; - - var sut = new ClassicReportBuilder(); - ReportApprover.Approve(model, sut); - } - - [Fact] - [MethodImpl(MethodImplOptions.NoInlining)] - public void ShouldProduceExpectedHtmlWithExamples() - { - var reportData = new ReportTestData().CreateTwoStoriesEachWithOneFailingScenarioAndOnePassingScenarioWithThreeStepsOfFiveMillisecondsAndEachHasTwoExamples().ToReportModel(); - var model = new HtmlReportModel(reportData) - { - RunDate = new DateTime(2014, 3, 25, 11, 30, 5) - }; - - var sut = new ClassicReportBuilder(); - ReportApprover.Approve(model, sut); - } - } -} -#endif \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Reporters/Html/HtmlReporterTests.cs b/src/TestStack.BDDfy.Tests/Reporters/Html/HtmlReporterTests.cs deleted file mode 100644 index bfa0b4ca..00000000 --- a/src/TestStack.BDDfy.Tests/Reporters/Html/HtmlReporterTests.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using NSubstitute; -using Shouldly; -using TestStack.BDDfy.Reporters; -using Xunit; - -namespace TestStack.BDDfy.Tests.Reporters.Html -{ - public class HtmlReporterTests - { - private TestableHtmlReporter _sut; - private const string OutputPath = @"C:\Reports"; - private const string ReportData = "Report Data"; - private const string CustomStylesheet = "some custom css in here!"; - private const string CustomJavascript = "some custom javascript in here!"; - private const string ErrorMessage = "There was some exception."; - - public HtmlReporterTests() - { - _sut = TestableHtmlReporter.Create(); - } - - [Fact] - public void ShouldCreateReportIfProcessingSucceeds() - { - _sut.ReportBuilder.CreateReport(Arg.Any()).Returns(ReportData); - - _sut.Process(new List()); - - _sut.Writer.Received().OutputReport(ReportData, Arg.Any(), Arg.Any()); - } - - [Fact] - public void ShouldPrintErrorInReportIfProcessingFails() - { - _sut.ReportBuilder.CreateReport(Arg.Any()).Returns(x => { throw new Exception(ErrorMessage); }); - - _sut.Process(new ReportTestData().CreateTwoStoriesEachWithOneFailingScenarioAndOnePassingScenarioWithThreeStepsOfFiveMilliseconds()); - - _sut.Writer.Received().OutputReport( - Arg.Is(s => s.StartsWith(ErrorMessage)), - Arg.Any(), - Arg.Any()); - } - - [Fact] - public void ShouldLoadCustomStyleSheetIfOneExists() - { - var customStylesheetFilePath = Path.Combine(OutputPath, "BDDfyCustom.css"); - - _sut.Configuration.OutputPath.Returns(OutputPath); - _sut.FileReader.Exists(customStylesheetFilePath).Returns(true); - _sut.FileReader.Read(customStylesheetFilePath).Returns(CustomStylesheet); - - _sut.Process(new ReportTestData().CreateTwoStoriesEachWithOneFailingScenarioAndOnePassingScenarioWithThreeStepsOfFiveMilliseconds()); - - _sut.Model.CustomStylesheet.ShouldBe(CustomStylesheet); - _sut.FileReader.Received().Read(customStylesheetFilePath); - } - - [Fact] - public void ShouldNotLoadCustomStyleSheetIfNoneExist() - { - var customStylesheet = Path.Combine(OutputPath, "BDDfyCustom.css"); - _sut.Configuration.OutputPath.Returns(OutputPath); - _sut.FileReader.Exists(customStylesheet).Returns(false); - - _sut.Process(new ReportTestData().CreateTwoStoriesEachWithOneFailingScenarioAndOnePassingScenarioWithThreeStepsOfFiveMilliseconds()); - - _sut.Model.CustomStylesheet.ShouldBe(null); - _sut.FileReader.DidNotReceive().Read(customStylesheet); - } - - [Fact] - public void ShouldLoadCustomJavascriptIfOneExists() - { - var javaScriptFilePath = Path.Combine(OutputPath, "BDDfyCustom.js"); - _sut.Configuration.OutputPath.Returns(OutputPath); - _sut.FileReader.Exists(javaScriptFilePath).Returns(true); - _sut.FileReader.Read(javaScriptFilePath).Returns(CustomJavascript); - - _sut.Process(new ReportTestData().CreateTwoStoriesEachWithOneFailingScenarioAndOnePassingScenarioWithThreeStepsOfFiveMilliseconds()); - - _sut.Model.CustomJavascript.ShouldBe(CustomJavascript); - _sut.FileReader.Received().Read(javaScriptFilePath); - } - - [Fact] - public void ShouldNotLoadCustomJavascriptIfNoneExist() - { - var customJavascript = Path.Combine(OutputPath, "BDDfyCustom.js"); - _sut.Configuration.OutputPath.Returns(OutputPath); - _sut.FileReader.Exists(customJavascript).Returns(false); - - _sut.Process(new ReportTestData().CreateTwoStoriesEachWithOneFailingScenarioAndOnePassingScenarioWithThreeStepsOfFiveMilliseconds()); - - _sut.Model.CustomJavascript.ShouldBe(null); - _sut.FileReader.DidNotReceive().Read(customJavascript); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Reporters/Html/MetroReportBuilderTests.ShouldProduceExpectedHtml.approved.txt b/src/TestStack.BDDfy.Tests/Reporters/Html/MetroReportBuilderTests.ShouldProduceExpectedHtml.approved.txt deleted file mode 100644 index e9243409..00000000 --- a/src/TestStack.BDDfy.Tests/Reporters/Html/MetroReportBuilderTests.ShouldProduceExpectedHtml.approved.txt +++ /dev/null @@ -1,301 +0,0 @@ - - - - - - - - BDDfy Test Result 25/03/2014 - - -
-
-

BDDfy

-

A simple BDD framework for .Net developers

-
-
- -
-
-
-

results

- show steps - hide steps -
-
    -
  • -
    - -
    -
    -
    Happy Path Scenario
    -
      -
    • - Given a positive account balance -
    • -
    • - When the account holder requests money -
    • -
    • - Then money is dispensed -
    • -
    -
    -
    -
    Inconclusive Scenario
    -
      -
    • - Given a negative account balance -
    • -
    • - When the account holder requests money -
    • -
    • - Then no money is dispensed -
    • -
    -
    -
    -
    Not Implemented Scenario
    -
      -
    • - Given a negative account balance -
    • -
    • - When the account holder requests money -
    • -
    • - Then no money is dispensed -
    • -
    -
    -
    -
    Sad Path Scenario
    -
      -
    • - Given a negative account balance -
    • -
    • - When the account holder requests money -
    • -
    • - Then no money is dispensed [Exception Message: 'Boom'] -
      - at TestStack.BDDfy.Tests.Reporters.ReportTestData.GetOneOfEachScenarioResult() in ...\ReportTestData.cs -
      -
    • -
    -
    -
    -
    -
  • -
  • -
    - -
    -
    -
    Happy Path Scenario
    -
      -
    • - Given a positive account balance -
    • -
    • - When the account holder requests money -
    • -
    • - Then money is dispensed -
    • -
    -
    -
    -
    Inconclusive Scenario
    -
      -
    • - Given a negative account balance -
    • -
    • - When the account holder requests money -
    • -
    • - Then no money is dispensed -
    • -
    -
    -
    -
    Not Implemented Scenario
    -
      -
    • - Given a negative account balance -
    • -
    • - When the account holder requests money -
    • -
    • - Then no money is dispensed -
    • -
    -
    -
    -
    Sad Path Scenario
    -
      -
    • - Given a negative account balance -
    • -
    • - When the account holder requests money -
    • -
    • - Then no money is dispensed [Exception Message: 'Boom'] -
      - at TestStack.BDDfy.Tests.Reporters.ReportTestData.GetOneOfEachScenarioResult() in ...\ReportTestData.cs -
      -
    • -
    -
    -
    -
    -
  • -
  • -
    - -
    -
    -
    Happy Path Scenario
    -
      -
    • - Given a positive account balance -
    • -
    • - When the account holder requests money -
    • -
    • - Then money is dispensed -
    • -
    -
    -
    -
    Inconclusive Scenario
    -
      -
    • - Given a negative account balance -
    • -
    • - When the account holder requests money -
    • -
    • - Then no money is dispensed -
    • -
    -
    -
    -
    Not Implemented Scenario
    -
      -
    • - Given a negative account balance -
    • -
    • - When the account holder requests money -
    • -
    • - Then no money is dispensed -
    • -
    -
    -
    -
    Sad Path Scenario
    -
      -
    • - Given a negative account balance -
    • -
    • - When the account holder requests money -
    • -
    • - Then no money is dispensed [Exception Message: 'Boom'] -
      - at TestStack.BDDfy.Tests.Reporters.ReportTestData.GetOneOfEachScenarioResult() in ...\ReportTestData.cs -
      -
    • -
    -
    -
    -
    -
  • -
-
-
-
-

Tested at: 25/03/2014 11:30:05

-

Powered by BDDfy

-
- - - - - diff --git a/src/TestStack.BDDfy.Tests/Reporters/Html/MetroReportBuilderTests.ShouldProduceExpectedHtmlWithExamples.approved.txt b/src/TestStack.BDDfy.Tests/Reporters/Html/MetroReportBuilderTests.ShouldProduceExpectedHtmlWithExamples.approved.txt deleted file mode 100644 index 944cc5dc..00000000 --- a/src/TestStack.BDDfy.Tests/Reporters/Html/MetroReportBuilderTests.ShouldProduceExpectedHtmlWithExamples.approved.txt +++ /dev/null @@ -1,194 +0,0 @@ - - - - - - - - BDDfy Test Result 25/03/2014 - - -
-
-

BDDfy

-

A simple BDD framework for .Net developers

-
-
- -
-
-
-

results

- show steps - hide steps -
-
    -
  • -
    - -
    -
    -
    Example Scenario
    -
      -
    • - Given a <sign> account balance -
    • -
    • - When the account holder requests money -
    • -
    • - Then money <action> dispensed -
    • -
    • - Examples: - - - - - - - - - - - - - - - - - - - -
      signactionError
      positiveis -
      negativeis not - Boom -With -New lines -
      - at TestStack.BDDfy.Tests.Reporters.ReportTestData.GetScenarios(Boolean includeFailingScenario, Boolean includeExamples) in ...\ReportTestData.cs -
      -
      -
    • -
    -
    -
    -
    -
  • -
  • -
    - -
    -
    -
    Example Scenario
    -
      -
    • - Given a <sign> account balance -
    • -
    • - When the account holder requests money -
    • -
    • - Then money <action> dispensed -
    • -
    • - Examples: - - - - - - - - - - - - - - - - -
      signaction
      positiveis
      negativeis not
      -
    • -
    -
    -
    -
    -
  • -
-
-
-
-

Tested at: 25/03/2014 11:30:05

-

Powered by BDDfy

-
- - - - - diff --git a/src/TestStack.BDDfy.Tests/Reporters/Html/MetroReportBuilderTests.cs b/src/TestStack.BDDfy.Tests/Reporters/Html/MetroReportBuilderTests.cs deleted file mode 100644 index c135aaa1..00000000 --- a/src/TestStack.BDDfy.Tests/Reporters/Html/MetroReportBuilderTests.cs +++ /dev/null @@ -1,42 +0,0 @@ -#if Approvals -using System; -using System.Runtime.CompilerServices; -using TestStack.BDDfy.Reporters; -using TestStack.BDDfy.Reporters.Html; -using Xunit; - -namespace TestStack.BDDfy.Tests.Reporters.Html -{ - public class MetroReportBuilderTests - { - [Fact] - [MethodImpl(MethodImplOptions.NoInlining)] - public void ShouldProduceExpectedHtml() - { - var model = - new HtmlReportModel(new ReportTestData().CreateMixContainingEachTypeOfOutcome().ToReportModel()) - { - RunDate = new DateTime(2014, 3, 25, 11, 30, 5) - }; - - var sut = new MetroReportBuilder(); - ReportApprover.Approve(model, sut); - } - - [Fact] - [MethodImpl(MethodImplOptions.NoInlining)] - public void ShouldProduceExpectedHtmlWithExamples() - { - var model = - new HtmlReportModel(new ReportTestData().CreateTwoStoriesEachWithOneFailingScenarioAndOnePassingScenarioWithThreeStepsOfFiveMillisecondsAndEachHasTwoExamples() - .ToReportModel()) - { - RunDate = new DateTime(2014, 3, 25, 11, 30, 5) - }; - - var sut = new MetroReportBuilder(); - ReportApprover.Approve(model, sut); - } - } -} -#endif \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Reporters/Html/TemporaryCulture.cs b/src/TestStack.BDDfy.Tests/Reporters/Html/TemporaryCulture.cs deleted file mode 100644 index 5ffed717..00000000 --- a/src/TestStack.BDDfy.Tests/Reporters/Html/TemporaryCulture.cs +++ /dev/null @@ -1,23 +0,0 @@ -#if Culture -using System; -using System.Globalization; -using System.Threading; - -namespace TestStack.BDDfy.Tests.Reporters.Html -{ - public class TemporaryCulture : IDisposable - { - private readonly string _originalCulture; - public TemporaryCulture(string newCulture) - { - _originalCulture = Thread.CurrentThread.CurrentCulture.Name; - Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(newCulture); - } - - public void Dispose() - { - Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(_originalCulture); - } - } -} -#endif \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Reporters/Html/TestableHtmlReporter.cs b/src/TestStack.BDDfy.Tests/Reporters/Html/TestableHtmlReporter.cs deleted file mode 100644 index fb233032..00000000 --- a/src/TestStack.BDDfy.Tests/Reporters/Html/TestableHtmlReporter.cs +++ /dev/null @@ -1,32 +0,0 @@ -using NSubstitute; -using TestStack.BDDfy.Reporters; -using TestStack.BDDfy.Reporters.Html; -using TestStack.BDDfy.Reporters.Readers; -using TestStack.BDDfy.Reporters.Writers; - -namespace TestStack.BDDfy.Tests.Reporters.Html -{ - public class TestableHtmlReporter : HtmlReporter - { - public IHtmlReportConfiguration Configuration { get; set; } - public IReportWriter Writer { get; set; } - public IFileReader FileReader { get; set; } - - public TestableHtmlReporter(IHtmlReportConfiguration configuration, IReportBuilder reportBuilder, IReportWriter writer, IFileReader fileReader) - : base(configuration, reportBuilder, writer, fileReader) - { - Configuration = configuration; - ReportBuilder = reportBuilder; - Writer = writer; - FileReader = fileReader; - Configuration.RunsOn(Arg.Any()).Returns(true); - } - - public static TestableHtmlReporter Create() - { - return new TestableHtmlReporter( - Substitute.For(), Substitute.For(), - Substitute.For(), Substitute.For()); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Reporters/MarkDown/MarkDownReportBuilderTests.ShouldProduceExpectedMarkdown.approved.txt b/src/TestStack.BDDfy.Tests/Reporters/MarkDown/MarkDownReportBuilderTests.ShouldProduceExpectedMarkdown.approved.txt deleted file mode 100644 index 22929959..00000000 --- a/src/TestStack.BDDfy.Tests/Reporters/MarkDown/MarkDownReportBuilderTests.ShouldProduceExpectedMarkdown.approved.txt +++ /dev/null @@ -1,71 +0,0 @@ -## Story: Account holder withdraws cash - **As an account holder** - **I want to withdraw cash** - **So that I can get money when the bank is closed** - -### Happy Path Scenario - Given a positive account balance - When the account holder requests money - Then money is dispensed - -### Inconclusive Scenario - Given a negative account balance - When the account holder requests money - Then no money is dispensed - -### Not Implemented Scenario - Given a negative account balance - When the account holder requests money - Then no money is dispensed - -### Sad Path Scenario - Given a negative account balance - When the account holder requests money - Then no money is dispensed - -## Story: Happiness - **As a person** - **I want ice cream** - **So that I can be happy** - -### Happy Path Scenario - Given a positive account balance - When the account holder requests money - Then money is dispensed - -### Inconclusive Scenario - Given a negative account balance - When the account holder requests money - Then no money is dispensed - -### Not Implemented Scenario - Given a negative account balance - When the account holder requests money - Then no money is dispensed - -### Sad Path Scenario - Given a negative account balance - When the account holder requests money - Then no money is dispensed - - -### Happy Path Scenario - Given a positive account balance - When the account holder requests money - Then money is dispensed - -### Inconclusive Scenario - Given a negative account balance - When the account holder requests money - Then no money is dispensed - -### Not Implemented Scenario - Given a negative account balance - When the account holder requests money - Then no money is dispensed - -### Sad Path Scenario - Given a negative account balance - When the account holder requests money - Then no money is dispensed - diff --git a/src/TestStack.BDDfy.Tests/Reporters/MarkDown/MarkDownReportBuilderTests.ShouldProduceExpectedMarkdownWithExamples.approved.txt b/src/TestStack.BDDfy.Tests/Reporters/MarkDown/MarkDownReportBuilderTests.ShouldProduceExpectedMarkdownWithExamples.approved.txt deleted file mode 100644 index 402c4762..00000000 --- a/src/TestStack.BDDfy.Tests/Reporters/MarkDown/MarkDownReportBuilderTests.ShouldProduceExpectedMarkdownWithExamples.approved.txt +++ /dev/null @@ -1,35 +0,0 @@ -## Story: Account holder withdraws cash - **As an account holder** - **I want to withdraw cash** - **So that I can get money when the bank is closed** - -### Example Scenario - Given a <sign> account balance - When the account holder requests money - Then money <action> dispensed - -### Examples: - - | sign | action | Result | Errors | - | positive | is | Passed | | - | negative | is not | Failed | Step: Then money <action> dispensed failed with exception: [Boom With New lines] [Details at 1 below] | - -#### Exceptions: - 1. Boom With New lines - at TestStack.BDDfy.Tests.Reporters.ReportTestData.GetScenarios(Boolean includeFailingScenario, Boolean includeExamples) in ...\ReportTestData.cs - -## Story: Happiness - **As a person** - **I want ice cream** - **So that I can be happy** - -### Example Scenario - Given a <sign> account balance - When the account holder requests money - Then money <action> dispensed - -### Examples: - - | sign | action | - | positive | is | - | negative | is not | diff --git a/src/TestStack.BDDfy.Tests/Reporters/MarkDown/MarkDownReportBuilderTests.cs b/src/TestStack.BDDfy.Tests/Reporters/MarkDown/MarkDownReportBuilderTests.cs deleted file mode 100644 index 2924d3ba..00000000 --- a/src/TestStack.BDDfy.Tests/Reporters/MarkDown/MarkDownReportBuilderTests.cs +++ /dev/null @@ -1,37 +0,0 @@ -#if Approvals -using System; -using System.Runtime.CompilerServices; -using TestStack.BDDfy.Reporters; -using TestStack.BDDfy.Reporters.MarkDown; -using Xunit; - -namespace TestStack.BDDfy.Tests.Reporters.MarkDown -{ - public class MarkDownReportBuilderTests - { - [Fact] - [MethodImpl(MethodImplOptions.NoInlining)] - public void ShouldProduceExpectedMarkdown() - { - var model = new FileReportModel(new ReportTestData().CreateMixContainingEachTypeOfOutcome().ToReportModel()); - var sut = new MarkDownReportBuilder(); - ReportApprover.Approve(model, sut); - } - - [Fact] - [MethodImpl(MethodImplOptions.NoInlining)] - public void ShouldProduceExpectedMarkdownWithExamples() - { - var model = - new FileReportModel(new ReportTestData().CreateTwoStoriesEachWithOneFailingScenarioAndOnePassingScenarioWithThreeStepsOfFiveMillisecondsAndEachHasTwoExamples() - .ToReportModel()) - { - RunDate = new DateTime(2014, 3, 25, 11, 30, 5) - }; - - var sut = new MarkDownReportBuilder(); - ReportApprover.Approve(model, sut); - } - } -} -#endif \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Reporters/MarkDown/MarkDownReporterTests.cs b/src/TestStack.BDDfy.Tests/Reporters/MarkDown/MarkDownReporterTests.cs deleted file mode 100644 index 7b71f6ca..00000000 --- a/src/TestStack.BDDfy.Tests/Reporters/MarkDown/MarkDownReporterTests.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Collections.Generic; -using NSubstitute; -using TestStack.BDDfy.Reporters; -using TestStack.BDDfy.Reporters.MarkDown; -using TestStack.BDDfy.Reporters.Writers; -using Xunit; - -namespace TestStack.BDDfy.Tests.Reporters.MarkDown -{ - public class MarkDownReporterTests - { - private IReportBuilder _builder; - private IReportWriter _writer; - - [Fact] - public void ShouldCreateReportIfProcessingSucceeds() - { - var sut = CreateSut(); - _builder.CreateReport(Arg.Any()).Returns("Report Data"); - - sut.Process(new List()); - - _writer.Received().OutputReport("Report Data", Arg.Any(), Arg.Any()); - } - - [Fact] - public void ShouldPrintErrorInReportIfProcessingFails() - { - var sut = CreateSut(); - _builder.CreateReport(Arg.Any()).Returns(x => { throw new Exception("Error occurred."); }); - - sut.Process(new List()); - - _writer.Received().OutputReport( - Arg.Is(s => s.StartsWith("Error occurred.")), - Arg.Any(), - Arg.Any()); - } - - private MarkDownReporter CreateSut() - { - _builder = Substitute.For(); - _writer = Substitute.For(); - return new MarkDownReporter(_builder, _writer); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Reporters/ReportApprover.cs b/src/TestStack.BDDfy.Tests/Reporters/ReportApprover.cs deleted file mode 100644 index b89b6d2b..00000000 --- a/src/TestStack.BDDfy.Tests/Reporters/ReportApprover.cs +++ /dev/null @@ -1,45 +0,0 @@ -#if Approvals -using System.Text.RegularExpressions; -using Shouldly; -using TestStack.BDDfy.Reporters; -using TestStack.BDDfy.Tests.Reporters.Html; - -namespace TestStack.BDDfy.Tests.Reporters -{ - class ReportApprover - { - public static void Approve(FileReportModel model, IReportBuilder reportBuilder) - { - // setting the culture to make sure the date is formatted the same on all machines - using (new TemporaryCulture("en-GB")) - { - var result = reportBuilder.CreateReport(model); - result.ShouldMatchApproved(c => c - .WithScrubber(Scrub) - .UseCallerLocation()); - } - } - - public static string Scrub(string scrubPaths) - { - return ScrubLineNumbers(ScrubPaths( - Regex.Replace( - Regex.Replace(Regex.Replace(scrubPaths, @"(? _stories; - - public ReportModelMapperTests() - { - _stories = new ReportTestData().CreateTwoStoriesEachWithOneFailingScenarioAndOnePassingScenarioWithThreeStepsOfFiveMillisecondsAndEachHasTwoExamples() - .ToList(); - } - - [Fact] - public void story_should_map_to_report_story() - { - var mapped = _stories.ToReportModel().Stories; - - mapped.Count.ShouldBe(2); - for (int i = 0; i < 2; i++) - { - mapped[i].Namespace.ShouldBe(_stories[i].Namespace); - mapped[i].Result.ShouldBe(_stories[i].Result); - mapped[i].Scenarios.Count.ShouldBe(_stories[i].Scenarios.Count()); - mapped[i].Metadata.ShouldNotBe(null); - } - } - - [Fact] - public void story_metadata_should_map_to_report_story_metadata() - { - var mapped = _stories.ToReportModel().Stories; - - for (int i = 0; i < 2; i++) - { - mapped[i].Metadata.Narrative1.ShouldBe(_stories[i].Metadata.Narrative1); - mapped[i].Metadata.Narrative2.ShouldBe(_stories[i].Metadata.Narrative2); - mapped[i].Metadata.Narrative3.ShouldBe(_stories[i].Metadata.Narrative3); - mapped[i].Metadata.Title.ShouldBe(_stories[i].Metadata.Title); - mapped[i].Metadata.TitlePrefix.ShouldBe(_stories[i].Metadata.TitlePrefix); - mapped[i].Metadata.Type.ShouldBe(_stories[i].Metadata.Type); - mapped[i].Metadata.ImageUri.ShouldBe(_stories[i].Metadata.ImageUri); - mapped[i].Metadata.StoryUri.ShouldBe(_stories[i].Metadata.StoryUri); - } - } - - [Fact] - public void scenario_should_map_to_report_scenario() - { - var scenarios = _stories[0].Scenarios.ToList(); - var mapped = _stories.ToReportModel().Stories[0].Scenarios; - - for (int i = 0; i < 2; i++) - { - mapped[i].Id.ShouldBe(scenarios[i].Id); - mapped[i].Title.ShouldBe(scenarios[i].Title); - mapped[i].Example.ShouldNotBe(null); - mapped[i].Duration.ShouldBe(scenarios[i].Duration); - mapped[i].Result.ShouldBe(scenarios[i].Result); - - mapped[i].Tags.Count.ShouldBe(scenarios[i].Tags.Count); - mapped[i].Steps.Count.ShouldBe(scenarios[i].Steps.Count); - } - } - - [Fact] - public void step_should_map_to_report_step() - { - var steps = _stories[0].Scenarios.First().Steps; - var mapped = _stories.ToReportModel().Stories[0].Scenarios.First().Steps; - - for (int i = 0; i < 2; i++) - { - mapped[i].Id.ShouldBe(steps[i].Id); - mapped[i].Asserts.ShouldBe(steps[i].Asserts); - mapped[i].ShouldReport.ShouldBe(steps[i].ShouldReport); - mapped[i].Title.ShouldBe(steps[i].Title); - mapped[i].ExecutionOrder.ShouldBe(steps[i].ExecutionOrder); - mapped[i].Result.ShouldBe(steps[i].Result); - mapped[i].Exception.ShouldBe(steps[i].Exception); - mapped[i].Duration.ShouldBe(steps[i].Duration); - } - } - - [Fact] - public void example_should_map_to_report_example() - { - var scenarios = _stories[0].Scenarios.ToList(); - var mapped = _stories.ToReportModel().Stories[0].Scenarios; - - for (int i = 0; i < 2; i++) - { - mapped[i].Example.Headers.ShouldBe(scenarios[i].Example.Headers); - mapped[i].Example.Values.ShouldBe(scenarios[i].Example.Values); - } - } - } -} diff --git a/src/TestStack.BDDfy.Tests/Reporters/ReportTestData.cs b/src/TestStack.BDDfy.Tests/Reporters/ReportTestData.cs deleted file mode 100644 index d6da41d4..00000000 --- a/src/TestStack.BDDfy.Tests/Reporters/ReportTestData.cs +++ /dev/null @@ -1,282 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace TestStack.BDDfy.Tests.Reporters -{ - using System.Linq; - - public class ReportTestData - { - private int _idCount; - - public IEnumerable CreateTwoStoriesEachWithOneFailingScenarioAndOnePassingScenarioWithThreeStepsOfFiveMilliseconds() - { - var storyMetadata1 = new StoryMetadata(typeof(RegularAccountHolderStory), "As a person", "I want ice cream", "So that I can be happy", "Happiness"); - var storyMetadata2 = new StoryMetadata(typeof(GoldAccountHolderStory), "As an account holder", "I want to withdraw cash", "So that I can get money when the bank is closed", "Account holder withdraws cash"); - var stories = new List - { - new(storyMetadata1, GetScenarios(false, false)), - new(storyMetadata2, GetScenarios(true, false)) - }; - - return stories; - } - - public IEnumerable CreateMixContainingEachTypeOfOutcome() - { - var storyMetadata1 = new StoryMetadata(typeof(RegularAccountHolderStory), "As a person", "I want ice cream", "So that I can be happy", "Happiness"); - var storyMetadata2 = new StoryMetadata(typeof(GoldAccountHolderStory), "As an account holder", "I want to withdraw cash", "So that I can get money when the bank is closed", "Account holder withdraws cash"); - - const StoryMetadata testThatReportWorksWithNoStory = null; - - var stories = new List - { - new(storyMetadata1, GetOneOfEachScenarioResult()), - new(storyMetadata2, GetOneOfEachScenarioResult()), - new(testThatReportWorksWithNoStory, GetOneOfEachScenarioResult()) - }; - - return stories; - } - - public IEnumerable CreateMixContainingEachTypeOfOutcomeWithOneScenarioPerStory() - { - var storyMetadata1 = new StoryMetadata(typeof(RegularAccountHolderStory), "As a person", "I want ice cream", "So that I can be happy", "Happiness"); - var storyMetadata2 = new StoryMetadata(typeof(GoldAccountHolderStory), "As an unhappy examples story", "I want to see failed steps", "So that I can diagnose what's wrong", "Unhappy examples"); - var storyMetadata3 = new StoryMetadata(typeof(PlatinumAccountHolderStory), "As a happy examples story", "I want a clean report with examples", "So that the report is clean and readable", "Happy Examples"); - - const StoryMetadata testThatReportWorksWithNoStory = null; - - var stories = new List - { - new(storyMetadata1, new Scenario(typeof(HappyPathScenario), GetHappyExecutionSteps(), "Happy Path Scenario [for Happiness]", new List())), - new(storyMetadata1, new Scenario(typeof(SadPathScenario), GetFailingExecutionSteps(), "Sad Path Scenario [for Happiness]", new List())), - new(storyMetadata1, new Scenario(typeof(SadPathScenario), GetInconclusiveExecutionSteps(), "Inconclusive Scenario [for Happiness]", new List())), - new(storyMetadata1, new Scenario(typeof(SadPathScenario), GetNotImplementedExecutionSteps(), "Not Implemented Scenario [for Happiness]", new List())), - new(testThatReportWorksWithNoStory, new Scenario(typeof(HappyPathScenario), GetHappyExecutionSteps(), "Happy Path Scenario [with no story]", new List())), - new(testThatReportWorksWithNoStory, new Scenario(typeof(SadPathScenario), GetFailingExecutionSteps(), "Sad Path Scenario [with no story]", new List())), - new(testThatReportWorksWithNoStory, new Scenario(typeof(SadPathScenario), GetInconclusiveExecutionSteps(), "Inconclusive Scenario [with no story]", new List())), - new(testThatReportWorksWithNoStory, new Scenario(typeof(SadPathScenario), GetNotImplementedExecutionSteps(), "Not Implemented Scenario [with no story]", new List())), - new(storyMetadata2, GetScenarios(true, true)), - new(storyMetadata3, GetScenarios(false, true)), - }; - - return stories; - } - - public IEnumerable CreateTwoStoriesEachWithOneFailingScenarioAndOnePassingScenarioWithThreeStepsOfFiveMillisecondsAndEachHasTwoExamples() - { - var storyMetadata1 = new StoryMetadata(typeof(RegularAccountHolderStory), "As a person", "I want ice cream", "So that I can be happy", "Happiness"); - var storyMetadata2 = new StoryMetadata(typeof(GoldAccountHolderStory), "As an account holder", "I want to withdraw cash", "So that I can get money when the bank is closed", "Account holder withdraws cash"); - var stories = new List - { - new(storyMetadata1, GetScenarios(false, true)), - new(storyMetadata2, GetScenarios(true, true)) - }; - - return stories; - } - - private Scenario[] GetScenarios(bool includeFailingScenario, bool includeExamples) - { - var sadExecutionSteps = GetSadExecutionSteps().ToList(); - if (includeFailingScenario) - { - var last = sadExecutionSteps.Last(); - last.Result = Result.Failed; - try - { - throw new InvalidOperationException("Boom"); - } - catch (Exception ex) - { - last.Exception = ex; - } - } - - if (includeExamples) - { - var exampleId = _idCount++.ToString(); - var exampleTable = new ExampleTable("sign", "action") - { - {"positive", "is"}, - {"negative", "is not"} - }; - var exampleExecutionSteps = GetExampleExecutionSteps().ToList(); - if (includeFailingScenario) - { - var last = exampleExecutionSteps.Last(); - last.Result = Result.Failed; - try - { - throw new InvalidOperationException("Boom\nWith\r\nNew lines"); - } - catch (Exception ex) - { - last.Exception = ex; - } - } - return new List - { - new(exampleId, typeof(ExampleScenario), GetExampleExecutionSteps(), "Example Scenario", exampleTable.ElementAt(0), new List()), - new(exampleId, typeof(ExampleScenario), exampleExecutionSteps, "Example Scenario", exampleTable.ElementAt(1), new List()) - }.ToArray(); - } - - return new List - { - new(typeof(HappyPathScenario), GetHappyExecutionSteps(), "Happy Path Scenario", new List()), - new(typeof(SadPathScenario), sadExecutionSteps, "Sad Path Scenario", new List()) - }.ToArray(); - } - - private Scenario[] GetOneOfEachScenarioResult() - { - var scenarios = new List - { - new(typeof(HappyPathScenario), GetHappyExecutionSteps(), "Happy Path Scenario", new List()), - new(typeof(SadPathScenario), GetSadExecutionSteps(), "Sad Path Scenario", new List()), - new(typeof(SadPathScenario), GetInconclusiveExecutionSteps(), "Inconclusive Scenario", new List()), - new(typeof(SadPathScenario), GetNotImplementedExecutionSteps(), "Not Implemented Scenario", new List()) - }; - - // override specific step results - ideally this class could be refactored to provide objectmother/builder interface - SetAllStepResults(scenarios[0].Steps, Result.Passed); - - SetAllStepResults(scenarios[1].Steps, Result.Passed); - var last = scenarios[1].Steps.Last(); - last.Result = Result.Failed; - try - { - throw new InvalidOperationException("Boom"); - } - catch (Exception ex) - { - last.Exception = ex; - } - - return scenarios.ToArray(); - } - - private List GetHappyExecutionSteps() - { - var steps = new List - { - new(null, new StepTitle("Given a positive account balance"), true, ExecutionOrder.Assertion, true, new List()) {Duration = new TimeSpan(0, 0, 0, 0, 5), Result = Result.Passed}, - new(null, new StepTitle("When the account holder requests money"), true, ExecutionOrder.Assertion, true, new List()) {Duration = new TimeSpan(0, 0, 0, 0, 5), Result = Result.Passed}, - new(null, new StepTitle("Then money is dispensed"), true, ExecutionOrder.Assertion, true, new List()) {Duration = new TimeSpan(0, 0, 0, 0, 5), Result = Result.Passed}, - }; - return steps; - } - - private List GetExampleExecutionSteps() - { - var steps = new List - { - new(null, new StepTitle("Given a account balance"), true, ExecutionOrder.Assertion, true, new List()) {Duration = new TimeSpan(0, 0, 0, 0, 5), Result = Result.Passed}, - new(null, new StepTitle("When the account holder requests money"), true, ExecutionOrder.Assertion, true, new List()) {Duration = new TimeSpan(0, 0, 0, 0, 5), Result = Result.Passed}, - new(null, new StepTitle("Then money dispensed"), true, ExecutionOrder.Assertion, true, new List()) {Duration = new TimeSpan(0, 0, 0, 0, 5), Result = Result.Passed}, - }; - return steps; - } - - private List GetSadExecutionSteps() - { - var steps = new List - { - new(null, new StepTitle("Given a negative account balance"), true, ExecutionOrder.Assertion, true, new List()) {Duration = new TimeSpan(0, 0, 0, 0, 5), Result = Result.Passed}, - new(null, new StepTitle("When the account holder requests money"), true, ExecutionOrder.Assertion, true, new List()) {Duration = new TimeSpan(0, 0, 0, 0, 5), Result = Result.Passed}, - new(null, new StepTitle("Then no money is dispensed"), true, ExecutionOrder.Assertion, true, new List()) {Duration = new TimeSpan(0, 0, 0, 0, 5), Result = Result.Passed}, - }; - return steps; - } - - private List GetFailingExecutionSteps() - { - var steps = new List - { - new(null, new StepTitle("Given a negative account balance"), true, ExecutionOrder.Assertion, true, new List()), - new(null, new StepTitle("When the account holder requests money"), true, ExecutionOrder.Assertion, true, new List()), - new(null, new StepTitle("Then no money is dispensed"), true, ExecutionOrder.Assertion, true, new List()), - }; - - SetAllStepResults(steps, Result.Passed); - - var last = steps.Last(); - last.Result = Result.Failed; - try - { - throw new InvalidOperationException("Boom"); - } - catch (Exception ex) - { - last.Exception = ex; - } - - return steps; - } - - private List GetInconclusiveExecutionSteps() - { - var steps = new List - { - new(null, new StepTitle("Given a negative account balance"), true, ExecutionOrder.Assertion, true, new List()) {Duration = new TimeSpan(0, 0, 0, 0, 5)}, - new(null, new StepTitle("When the account holder requests money"), true, ExecutionOrder.Assertion, true, new List()) {Duration = new TimeSpan(0, 0, 0, 0, 5)}, - new(null, new StepTitle("Then no money is dispensed"), true, ExecutionOrder.Assertion, true, new List()) {Duration = new TimeSpan(0, 0, 0, 0, 5)}, - }; - - SetAllStepResults(steps, Result.Passed); - - steps.Last().Result = Result.Inconclusive; - - return steps; - } - - - private List GetNotImplementedExecutionSteps() - { - var steps = new List - { - new(null, new StepTitle("Given a negative account balance"), true, ExecutionOrder.Assertion, true, new List()) {Duration = new TimeSpan(0, 0, 0, 0, 5)}, - new(null, new StepTitle("When the account holder requests money"), true, ExecutionOrder.Assertion, true, new List()) {Duration = new TimeSpan(0, 0, 0, 0, 5)}, - new(null, new StepTitle("Then no money is dispensed"), true, ExecutionOrder.Assertion, true, new List()) {Duration = new TimeSpan(0, 0, 0, 0, 5)}, - }; - - SetAllStepResults(steps, Result.Passed); - - steps.Last().Result = Result.NotImplemented; - - return steps; - } - - private void SetAllStepResults(IEnumerable steps, Result result) - { - foreach (var step in steps) - { - step.Result = result; - } - } - - public class RegularAccountHolderStory { } - public class GoldAccountHolderStory { } - public class PlatinumAccountHolderStory { } - public class ExampleScenario - { - public void GivenA__sign__AccountBalance() { } - public void WhenTheAccountHolderRequestsMoney() { } - public void ThenMoney__action__Dispensed() { } - } - public class HappyPathScenario - { - public void GivenAPositiveAccountBalance() { } - public void WhenTheAccountHolderRequestsMoney() { } - public void ThenMoneyIsDispensed() { } - } - public class SadPathScenario - { - public void GivenANegativeAccountBalance() { } - public void WhenTheAccountHolderRequestsMoney() { } - public void ThenNoMoneyIsDispensed() { } - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Reporters/TextReporter/TextReporterTests.LongStepName.approved.txt b/src/TestStack.BDDfy.Tests/Reporters/TextReporter/TextReporterTests.LongStepName.approved.txt deleted file mode 100644 index c8169c66..00000000 --- a/src/TestStack.BDDfy.Tests/Reporters/TextReporter/TextReporterTests.LongStepName.approved.txt +++ /dev/null @@ -1,13 +0,0 @@ -Story: Text reporter tests - -Scenario: Scenario Text - Given a normal length title [Not executed] - When something of normal length happens [Not executed] - Then some long state should be: #Title [Not executed] - -Some more stuff which is quite long on the second line - -And finally another really long line - And a normal length assertion [Not executed] - - diff --git a/src/TestStack.BDDfy.Tests/Reporters/TextReporter/TextReporterTests.ShouldProduceExpectedReport.approved.txt b/src/TestStack.BDDfy.Tests/Reporters/TextReporter/TextReporterTests.ShouldProduceExpectedReport.approved.txt deleted file mode 100644 index e0573806..00000000 --- a/src/TestStack.BDDfy.Tests/Reporters/TextReporter/TextReporterTests.ShouldProduceExpectedReport.approved.txt +++ /dev/null @@ -1,116 +0,0 @@ -Story: Happiness - As a person - I want ice cream - So that I can be happy - -Scenario: Happy Path Scenario [for Happiness] - Given a positive account balance - When the account holder requests money - Then money is dispensed - - -Story: Happiness - As a person - I want ice cream - So that I can be happy - -Scenario: Sad Path Scenario [for Happiness] - Given a negative account balance [Passed] - When the account holder requests money [Passed] - Then no money is dispensed [Failed] [Boom] [Details at 1 below] - -Exceptions: - 1. Boom - at TestStack.BDDfy.Tests.Reporters.ReportTestData.GetFailingExecutionSteps() in ...\ReportTestData.cs - - -Story: Happiness - As a person - I want ice cream - So that I can be happy - -Scenario: Inconclusive Scenario [for Happiness] - Given a negative account balance [Passed] - When the account holder requests money [Passed] - Then no money is dispensed [Inconclusive] - - -Story: Happiness - As a person - I want ice cream - So that I can be happy - -Scenario: Not Implemented Scenario [for Happiness] - Given a negative account balance [Passed] - When the account holder requests money [Passed] - Then no money is dispensed [Not implemented] - - - -Scenario: Happy Path Scenario [with no story] - Given a positive account balance - When the account holder requests money - Then money is dispensed - - - -Scenario: Sad Path Scenario [with no story] - Given a negative account balance [Passed] - When the account holder requests money [Passed] - Then no money is dispensed [Failed] [Boom] [Details at 1 below] - -Exceptions: - 1. Boom - at TestStack.BDDfy.Tests.Reporters.ReportTestData.GetFailingExecutionSteps() in ...\ReportTestData.cs - - - -Scenario: Inconclusive Scenario [with no story] - Given a negative account balance [Passed] - When the account holder requests money [Passed] - Then no money is dispensed [Inconclusive] - - - -Scenario: Not Implemented Scenario [with no story] - Given a negative account balance [Passed] - When the account holder requests money [Passed] - Then no money is dispensed [Not implemented] - - -Story: Unhappy examples - As an unhappy examples story - I want to see failed steps - So that I can diagnose what's wrong - -Scenario: Example Scenario - Given a account balance - When the account holder requests money - Then money dispensed - -Examples: -| sign | action | Result | Errors | -| positive | is | Passed | | -| negative | is not | Failed | Step: Then money dispensed failed with exception: [Boom With New lines] [Details at 1 below] | - -Exceptions: - 1. Boom With New lines - at TestStack.BDDfy.Tests.Reporters.ReportTestData.GetScenarios(Boolean includeFailingScenario, Boolean includeExamples) in ...\ReportTestData.cs - - -Story: Happy Examples - As a happy examples story - I want a clean report with examples - So that the report is clean and readable - -Scenario: Example Scenario - Given a account balance - When the account holder requests money - Then money dispensed - -Examples: -| sign | action | -| positive | is | -| negative | is not | - - diff --git a/src/TestStack.BDDfy.Tests/Reporters/TextReporter/TextReporterTests.ShouldProduceExpectedTextWithExamples.approved.txt b/src/TestStack.BDDfy.Tests/Reporters/TextReporter/TextReporterTests.ShouldProduceExpectedTextWithExamples.approved.txt deleted file mode 100644 index 53003403..00000000 --- a/src/TestStack.BDDfy.Tests/Reporters/TextReporter/TextReporterTests.ShouldProduceExpectedTextWithExamples.approved.txt +++ /dev/null @@ -1,36 +0,0 @@ -Story: Happiness - As a person - I want ice cream - So that I can be happy - -Scenario: Example Scenario - Given a account balance - When the account holder requests money - Then money dispensed - -Examples: -| sign | action | -| positive | is | -| negative | is not | - - -Story: Account holder withdraws cash - As an account holder - I want to withdraw cash - So that I can get money when the bank is closed - -Scenario: Example Scenario - Given a account balance - When the account holder requests money - Then money dispensed - -Examples: -| sign | action | Result | Errors | -| positive | is | Passed | | -| negative | is not | Failed | Step: Then money dispensed failed with exception: [Boom With New lines] [Details at 1 below] | - -Exceptions: - 1. Boom With New lines - at TestStack.BDDfy.Tests.Reporters.ReportTestData.GetScenarios(Boolean includeFailingScenario, Boolean includeExamples) in ...\ReportTestData.cs - - diff --git a/src/TestStack.BDDfy.Tests/Reporters/TextReporter/TextReporterTests.cs b/src/TestStack.BDDfy.Tests/Reporters/TextReporter/TextReporterTests.cs deleted file mode 100644 index d0ea304f..00000000 --- a/src/TestStack.BDDfy.Tests/Reporters/TextReporter/TextReporterTests.cs +++ /dev/null @@ -1,68 +0,0 @@ -#if Approvals -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using System.Text; -using Shouldly; -using TestStack.BDDfy.Reporters; -using Xunit; - -namespace TestStack.BDDfy.Tests.Reporters.MarkDown -{ - public class TextReporterTests - { - [Fact] - [MethodImpl(MethodImplOptions.NoInlining)] - public void ShouldProduceExpectedReport() - { - var stories = new ReportTestData().CreateMixContainingEachTypeOfOutcomeWithOneScenarioPerStory(); - var actual = new StringBuilder(); - - foreach (var story in stories) - { - var textReporter = new TextReporter(); - textReporter.Process(story); - actual.AppendLine(textReporter.ToString()); - } - - actual.ToString().ShouldMatchApproved(c => c.WithScrubber(ReportApprover.Scrub)); - } - - [Fact] - [MethodImpl(MethodImplOptions.NoInlining)] - public void ShouldProduceExpectedTextWithExamples() - { - var stories = new ReportTestData().CreateTwoStoriesEachWithOneFailingScenarioAndOnePassingScenarioWithThreeStepsOfFiveMillisecondsAndEachHasTwoExamples(); - var actual = new StringBuilder(); - - foreach (var story in stories) - { - var textReporter = new TextReporter(); - textReporter.Process(story); - actual.AppendLine(textReporter.ToString()); - } - - actual.ToString().ShouldMatchApproved(c => c.WithScrubber(ReportApprover.Scrub)); - } - - [Fact] - [MethodImpl(MethodImplOptions.NoInlining)] - public void LongStepName() - { - var textReporter = new TextReporter(); - var scenario = new Scenario(typeof(TextReporterTests), new List - { - new Step(o => null, new StepTitle("Given a normal length title"), false, ExecutionOrder.SetupState, true, new List()), - new Step(o => null, new StepTitle("When something of normal length happens"), false, ExecutionOrder.Transition, true, new List()), - new Step(o => null, new StepTitle("Then some long state should be: #Title\r\n\r\nSome more stuff which is quite long on the second line\r\n\r\nAnd finally another really long line"), - true, ExecutionOrder.Assertion, true, new List()), - new Step(o => null, new StepTitle("And a normal length assertion"), true, ExecutionOrder.ConsecutiveAssertion, true, new List()) - }, "Scenario Text", new List()); - textReporter.Process(new Story(new StoryMetadata(typeof(TextReporterTests), new StoryNarrativeAttribute()), - scenario)); - var actual = new StringBuilder(); - actual.AppendLine(textReporter.ToString()); - actual.ToString().ShouldMatchApproved(c => c.WithScrubber(ReportApprover.Scrub)); - } - } -} -#endif \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Scanner/Examples/ExampleActionTests.CanUseActionsInExamples.approved.txt b/src/TestStack.BDDfy.Tests/Scanner/Examples/ExampleActionTests.CanUseActionsInExamples.approved.txt deleted file mode 100644 index b53b0f99..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/Examples/ExampleActionTests.CanUseActionsInExamples.approved.txt +++ /dev/null @@ -1,11 +0,0 @@ - -Scenario: Can use actions in examples - Given some setup - When - Then should be - -Examples: -| Action to perform | Value should be | -| Do something | 42 | -| Do something else | 7 | - diff --git a/src/TestStack.BDDfy.Tests/Scanner/Examples/ExampleActionTests.cs b/src/TestStack.BDDfy.Tests/Scanner/Examples/ExampleActionTests.cs deleted file mode 100644 index 2f24641b..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/Examples/ExampleActionTests.cs +++ /dev/null @@ -1,44 +0,0 @@ -#if Approvals -using Shouldly; -using TestStack.BDDfy.Reporters; -using Xunit; - -namespace TestStack.BDDfy.Tests.Scanner.Examples -{ - public class ExampleActionTests - { - private int _value; - - [Fact] - public void CanUseActionsInExamples() - { - ExampleAction actionToPerform = null; - int valueShouldBe = 0; - var story = this.Given(_ => SomeSetup()) - .When(() => actionToPerform) - .Then(_ => ShouldBe(valueShouldBe)) - .WithExamples(new ExampleTable("Action to perform", "Value should be") - { - { new ExampleAction("Do something", () => { _value = 42; }), 42 }, - { new ExampleAction("Do something else", () => { _value = 7; }), 7 } - }) - .BDDfy(); - - - var textReporter = new TextReporter(); - textReporter.Process(story); - textReporter.ToString().ShouldMatchApproved(); - } - - private void ShouldBe(int i) - { - _value.ShouldBe(i); - } - - private void SomeSetup() - { - - } - } -} -#endif \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Scanner/Examples/ExampleTableTests.TableToString.approved.txt b/src/TestStack.BDDfy.Tests/Scanner/Examples/ExampleTableTests.TableToString.approved.txt deleted file mode 100644 index 67b8471d..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/Examples/ExampleTableTests.TableToString.approved.txt +++ /dev/null @@ -1,4 +0,0 @@ - -| Header 1 | Header 2 | -| 1 | 2 | -| 3 | 4 | diff --git a/src/TestStack.BDDfy.Tests/Scanner/Examples/ExampleTableTests.TableToStringWithAdditionalColumn.approved.txt b/src/TestStack.BDDfy.Tests/Scanner/Examples/ExampleTableTests.TableToStringWithAdditionalColumn.approved.txt deleted file mode 100644 index 19f76fef..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/Examples/ExampleTableTests.TableToStringWithAdditionalColumn.approved.txt +++ /dev/null @@ -1,4 +0,0 @@ - -| Header 1 | Header 2 | Additional | -| 1 | 2 | SomeAdditional Value | -| 3 | 4 | | diff --git a/src/TestStack.BDDfy.Tests/Scanner/Examples/ExampleTableTests.cs b/src/TestStack.BDDfy.Tests/Scanner/Examples/ExampleTableTests.cs deleted file mode 100644 index 47c98247..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/Examples/ExampleTableTests.cs +++ /dev/null @@ -1,59 +0,0 @@ -#if Approvals -using System; -using System.Linq; -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Tests.Scanner.Examples -{ - public class ExampleTableTests - { - [Fact] - public void CanParseTable() - { - const string table = @" -| Header 1 | Header 2 | Header3 | -| Value 1 | 2 | 3 | -| | 14 Mar 2010 | Transition |"; - - var exampleTable = ExampleTable.Parse(table); - - exampleTable.Headers.ShouldBe(new[] { "Header 1", "Header 2", "Header3" }); - exampleTable.ElementAt(0).GetValueOf(0, typeof(string)).ShouldBe("Value 1"); - exampleTable.ElementAt(0).GetValueOf(1, typeof(int)).ShouldBe(2); - exampleTable.ElementAt(0).GetValueOf(2, typeof(decimal)).ShouldBe(3m); - exampleTable.ElementAt(1).GetValueOf(0, typeof(string)).ShouldBe(null); - exampleTable.ElementAt(1).GetValueOf(0, typeof(int?)).ShouldBe(null); - exampleTable.ElementAt(1).GetValueOf(2, typeof(ExecutionOrder)).ShouldBe(ExecutionOrder.Transition); - var argException = Should.Throw(() => exampleTable.ElementAt(1).GetValueOf(0, typeof(int))); - argException.Message.ShouldBe("Cannot convert to Int32 (Column: 'Header 1', Row: 2)"); - exampleTable.ElementAt(1).GetValueOf(1, typeof(DateTime)).ShouldBe(new DateTime(2010, 3, 14)); - } - - [Fact] - public void TableToString() - { - var table = new ExampleTable("Header 1", "Header 2") - { - {1, 2}, - {3, 4} - }; - - table.ToString().ShouldMatchApproved(); - } - - [Fact] - public void TableToStringWithAdditionalColumn() - { - var table = new ExampleTable("Header 1", "Header 2") - { - {1, 2}, - {3, 4} - }; - - table.ToString(new[] {"Additional"}, new[] {new[] {"SomeAdditional Value"}}) - .ShouldMatchApproved(); - } - } -} -#endif \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Scanner/Examples/ExampleValueTests.cs b/src/TestStack.BDDfy.Tests/Scanner/Examples/ExampleValueTests.cs deleted file mode 100644 index d97fe3e2..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/Examples/ExampleValueTests.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Tests.Scanner.Examples -{ - public class ExampleValueTests - { - [Fact] - public void CanFormatAsStringTests() - { - new ExampleValue("Header", null, () => 0).GetValueAsString().ShouldBe("'null'"); - new ExampleValue("Header", 1, () => 0).GetValueAsString().ShouldBe("1"); - new ExampleValue("Header", new Object(), () => 0).GetValueAsString().ShouldBe("System.Object"); - new ExampleValue("Header", new[] {1, 2}, () => 0).GetValueAsString().ShouldBe("1, 2"); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Scanner/Examples/FluentWithExamples.FluentCanBeUsedWithExamples.approved.txt b/src/TestStack.BDDfy.Tests/Scanner/Examples/FluentWithExamples.FluentCanBeUsedWithExamples.approved.txt deleted file mode 100644 index b6d48ad7..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/Examples/FluentWithExamples.FluentCanBeUsedWithExamples.approved.txt +++ /dev/null @@ -1,15 +0,0 @@ - -Scenario: Fluent can be used with examples - Given method taking - And method taking - And a different method with random arg 2 - And a different method with - When method using - And I use a - Then all is good - -Examples: -| Prop 1 | Prop2 | Prop 3 | Multi word heading | -| 1 | foo | ConsecutiveAssertion | | -| 2 | bar | Initialize | val2 | - diff --git a/src/TestStack.BDDfy.Tests/Scanner/Examples/FluentWithExamples.Inline.approved.txt b/src/TestStack.BDDfy.Tests/Scanner/Examples/FluentWithExamples.Inline.approved.txt deleted file mode 100644 index a60b8b38..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/Examples/FluentWithExamples.Inline.approved.txt +++ /dev/null @@ -1,9 +0,0 @@ - -Scenario: Inline - Given int with value - -Examples: -| Inline Variable | -| 1 | -| 2 | - diff --git a/src/TestStack.BDDfy.Tests/Scanner/Examples/FluentWithExamples.cs b/src/TestStack.BDDfy.Tests/Scanner/Examples/FluentWithExamples.cs deleted file mode 100644 index 7e52f9d1..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/Examples/FluentWithExamples.cs +++ /dev/null @@ -1,110 +0,0 @@ -#if Approvals -using System.Runtime.CompilerServices; -using Shouldly; -using TestStack.BDDfy.Reporters; -using Xunit; - -namespace TestStack.BDDfy.Tests.Scanner.Examples -{ - public class FluentWithExamples - { - [Fact] - public void FluentCanBeUsedWithExamples() - { - var story = this - .Given(_ => MethodTaking__ExampleInt__(Prop1), false) - .And(_ => MethodTaking__ExampleInt__(_.Prop1), false) - .And(_ => ADifferentMethodWithRandomArg(2)) - .And(_ => ADifferentMethodWith(_prop2)) - .When(_ => WhenMethodUsing__ExampleString__()) - .And(_ => AndIUseA(multiWordHeading)) - .Then(_ => ThenAllIsGood()) - .WithExamples(new ExampleTable("Prop 1", "Prop2", "Prop 3", "Multi word heading") - { - {1, "foo", ExecutionOrder.ConsecutiveAssertion, "" }, - {2, "bar", ExecutionOrder.Initialize, "val2" } - }) - .BDDfy(); - - var textReporter = new TextReporter(); - textReporter.Process(story); - textReporter.ToString().ShouldMatchApproved(); - } - - private void GivenIntWithValue(int differentName) - { - differentName.ShouldBeOneOf(1, 2); - } - - [Fact] - [MethodImpl(MethodImplOptions.NoInlining)] - public void Inline() - { - // ReSharper disable once ConvertToConstant.Local - var inlineVariable = 0; - var story = this - .Given(_ => GivenIntWithValue(inlineVariable)) - .WithExamples(new ExampleTable("Inline Variable") { 1, 2 }) - .BDDfy(); - - var textReporter = new TextReporter(); - textReporter.Process(story); - textReporter.ToString().ShouldMatchApproved(); - } - - [Fact] - [MethodImpl(MethodImplOptions.NoInlining)] - public void ExampleTypeMismatch() - { - var ex = Should.Throw( - () => this.Given(() => WrongType.ShouldBe(1), "Given i use an example") - .WithExamples(new ExampleTable("Wrong type") - { - new object(), - new object[] { null } - }) - .BDDfy()); - - ex.Message.ShouldBe("System.Object cannot be assigned to Int32 (Column: 'Wrong type', Row: 1)"); - } - - private void AndIUseA(string multiWordHeading) - { - multiWordHeading.ShouldBeOneOf("", "val2"); - this.multiWordHeading.ShouldBeOneOf("", "val2"); - } - - private void ADifferentMethodWith(string prop2) - { - _prop2.ShouldBeOneOf("foo", "bar"); - } - - private void ADifferentMethodWithRandomArg(int foo) - { - - } - - private void ThenAllIsGood() - { - - } - - private void WhenMethodUsing__ExampleString__() - { - _prop2.ShouldBeOneOf("foo", "bar"); - Prop_3.ShouldBeOneOf(ExecutionOrder.ConsecutiveAssertion, ExecutionOrder.Initialize); - } - - private void MethodTaking__ExampleInt__(int exampleInt) - { - exampleInt.ShouldBeInRange(1, 2); - } - - public int WrongType { get; set; } - public int Prop1 { get; set; } - private string _prop2 = null; - private string multiWordHeading = null; - public ExecutionOrder Prop_3 { get; set; } - } -} -#endif \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Scanner/Examples/FluentWithExamplesAtEnd.FluentCanBeUsedWithExamples.approved.txt b/src/TestStack.BDDfy.Tests/Scanner/Examples/FluentWithExamplesAtEnd.FluentCanBeUsedWithExamples.approved.txt deleted file mode 100644 index 1b8ece92..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/Examples/FluentWithExamplesAtEnd.FluentCanBeUsedWithExamples.approved.txt +++ /dev/null @@ -1,6 +0,0 @@ - -Scenario: Fluent can be used with examples - Given method taking - When empty method - Then all is good - diff --git a/src/TestStack.BDDfy.Tests/Scanner/Examples/FluentWithExamplesAtEnd.FluentCanBeUsedWithExamplesEndingInANumber.approved.txt b/src/TestStack.BDDfy.Tests/Scanner/Examples/FluentWithExamplesAtEnd.FluentCanBeUsedWithExamplesEndingInANumber.approved.txt deleted file mode 100644 index 049f6ef0..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/Examples/FluentWithExamplesAtEnd.FluentCanBeUsedWithExamplesEndingInANumber.approved.txt +++ /dev/null @@ -1,6 +0,0 @@ - -Scenario: Fluent can be used with examples ending in a number - Given method taking - When empty method - Then all is good - diff --git a/src/TestStack.BDDfy.Tests/Scanner/Examples/FluentWithExamplesAtEnd.cs b/src/TestStack.BDDfy.Tests/Scanner/Examples/FluentWithExamplesAtEnd.cs deleted file mode 100644 index 8019f583..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/Examples/FluentWithExamplesAtEnd.cs +++ /dev/null @@ -1,57 +0,0 @@ -#if Approvals -using Shouldly; -using TestStack.BDDfy.Reporters; -using Xunit; - -namespace TestStack.BDDfy.Tests.Scanner.Examples -{ - public class FluentWithExamplesAtEnd - { - [Fact] - public void FluentCanBeUsedWithExamples() - { - var story = this - .Given(_ => MethodTaking__ExampleIntA__(1), false) - .When(_ => WhenEmptyMethod()) - .Then(_ => ThenAllIsGood()) - .BDDfy(); - - var textReporter = new TextReporter(); - textReporter.Process(story); - textReporter.ToString().ShouldMatchApproved(); - } - - // This test crashes BDDfy or causes an infinite loop - [Fact] - public void FluentCanBeUsedWithExamplesEndingInANumber() { - var story = this - .Given(_ => MethodTaking__ExampleInt1__(1), false) - .When(_ => WhenEmptyMethod()) - .Then(_ => ThenAllIsGood()) - .BDDfy(); - - var textReporter = new TextReporter(); - textReporter.Process(story); - textReporter.ToString().ShouldMatchApproved(); - } - - private void ThenAllIsGood() - { - } - - private void WhenEmptyMethod() - { - } - - // Ending an example name with a number seems to cause problems in BDDfy - private void MethodTaking__ExampleInt1__(int exampleInt) - { - exampleInt.ShouldBeInRange(1, 2); - } - - private void MethodTaking__ExampleIntA__(int exampleInt) { - exampleInt.ShouldBeInRange(1, 2); - } - } -} -#endif \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Scanner/Examples/ReflectiveWithExamples.Run.approved.txt b/src/TestStack.BDDfy.Tests/Scanner/Examples/ReflectiveWithExamples.Run.approved.txt deleted file mode 100644 index 5c79a453..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/Examples/ReflectiveWithExamples.Run.approved.txt +++ /dev/null @@ -1,10 +0,0 @@ - -Scenario: Reflective with examples - Given step with passed as parameter - And step with accessed via property - -Examples: -| First Example | Second Example | -| 1 | foo | -| 2 | bar | - diff --git a/src/TestStack.BDDfy.Tests/Scanner/Examples/ReflectiveWithExamples.cs b/src/TestStack.BDDfy.Tests/Scanner/Examples/ReflectiveWithExamples.cs deleted file mode 100644 index 79440bda..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/Examples/ReflectiveWithExamples.cs +++ /dev/null @@ -1,39 +0,0 @@ -#if Approvals -using Shouldly; -using TestStack.BDDfy.Reporters; -using Xunit; - -namespace TestStack.BDDfy.Tests.Scanner.Examples -{ - public class ReflectiveWithExamples - { - public string SecondExample { get; set; } - - public void GivenStepWith__FirstExample__PassedAsParameter(int firstExample) - { - firstExample.ShouldBeOneOf(1, 2); - } - - public void AndGivenStepWith__SecondExample__AccessedViaProperty() - { - SecondExample.ShouldBeOneOf("foo", "bar"); - } - - [Fact] - public void Run() - { - var story = this - .WithExamples(new ExampleTable("First Example", "Second Example") - { - {1, "foo"}, - {2, "bar"} - }) - .BDDfy(); - - var reporter = new TextReporter(); - reporter.Process(story); - reporter.ToString().ShouldMatchApproved(); - } - } -} -#endif \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/AmbiguousHeaderMatchTests.cs b/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/AmbiguousHeaderMatchTests.cs deleted file mode 100644 index 7e530df0..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/AmbiguousHeaderMatchTests.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Reflection; -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Tests.Scanner.FluentScanner -{ - public class AmbiguousHeaderMatchTests - { - private int _count; - - [Fact] - public void ThrowsWhenMultipleHeadersMatchParameterName() - { - // Act & Assert - var exception = Should.Throw(() => - { - this.Given(_ => GivenInput(_count)) // Will try to bind _count to both "count" and "Count" headers - .WithExamples(new ExampleTable("count", "Count") // Deliberately ambiguous headers - { - { 5, 10 } - }) - .BDDfy(); - }); - - exception.Message.ShouldBe("More than one headers for examples, match the parameter 'count' provided for 'GivenInput'"); - } - - private void GivenInput(int count) - { - // The method exists just to trigger the ambiguous header match - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/BDDfyUsingFluentApi.cs b/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/BDDfyUsingFluentApi.cs deleted file mode 100644 index 08e10ab2..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/BDDfyUsingFluentApi.cs +++ /dev/null @@ -1,319 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using NUnit.Framework; -using Shouldly; -using TestStack.BDDfy.Configuration; -using Xunit; - -namespace TestStack.BDDfy.Tests.Scanner.FluentScanner -{ - public enum SomeEnumForTesting - { - Value1, - Value2 - } - - public class SomeClassWithStaticMembers - { - public static string StringProp { get { return "asdfsadf"; } } - public static int IntProp { get { return 1; } } - } - - [Story( - Title = "BDDfy using fluent API", - AsA = "As a programmer", - IWant = "I want to be able to use fluent api to scan for steps", - SoThat = "So that I can be in full control of what is passed in")] - public class BDDfyUsingFluentApi - { - private string[] _arrayInput1; - private int[] _arrayInput2; - private int _primitiveInput2; - private string _primitiveInput1; - private SomeEnumForTesting _enumInput; - private Action _action; - - internal void GivenAnAction(Action actionInput) - { - _action = actionInput; - } - - internal void ThenCallingTheActionThrows() where T : Exception - { - Should.Throw(() => _action()); - } - - internal void GivenPrimitiveInputs(string input1, int input2) - { - _primitiveInput1 = input1; - _primitiveInput2 = input2; - } - - internal void GivenEnumInputs(SomeEnumForTesting input) - { - _enumInput = input; - } - - internal void GivenArrayInputs(string[] input1, int[] input2) - { - _arrayInput1 = input1; - _arrayInput2 = input2; - } - - internal void GivenEnumerableInputs(IEnumerable input1, IEnumerable input2) - { - _arrayInput1 = input1.ToArray(); - _arrayInput2 = input2.ToArray(); - } - - internal void ThenTheArgumentsArePassedInProperlyAndStoredOnTheSameObjectInstance(string expectedInput1, int expectedInput2) - { - _primitiveInput1.ShouldBe(expectedInput1); - _primitiveInput2.ShouldBe(expectedInput2); - } - - internal void ThenEnumArgumentIsPassedInProperlyAndStoredOnTheSameObjectInstance(SomeEnumForTesting expectedInput) - { - _enumInput.ShouldBe(expectedInput); - } - - internal void ThenTheArgumentsArePassedInProperlyAndStoredOnTheSameObjectInstance(IEnumerable expectedInput1, IEnumerable expectedInput2) - { - _arrayInput1.ShouldBe(expectedInput1); - _arrayInput2.ShouldBe(expectedInput2); - } - - string _primitiveInput1Field = "1"; - int _primitiveInput2Field = 2; - - SomeEnumForTesting _enumInputField = SomeEnumForTesting.Value2; - - public string PrimitiveInput1Property { get { return _primitiveInput1Field; } } - public int PrimitiveInput2Property { get { return _primitiveInput2Field; } } - - public SomeEnumForTesting EnumInputProperty { get { return _enumInputField; } } - - string[] _arrayInput1Field = new[] { "1", "2" }; - int[] _arrayInput2Field = new[] { 3, 4 }; - - private IEnumerable EnumerableString = new[] {"1", null, "2"}; - private IEnumerable EnumerableInt = new[] {1, 2}; - - public string[] ArrayInput1Property { get { return _arrayInput1Field; } } - public int[] ArrayInput2Property { get { return _arrayInput2Field; } } - - [Fact] - public void PassingPrimitiveArgumentsInline() - { - this.Given(x => x.GivenPrimitiveInputs("1", 2), "Given inline input arguments {0} and {1}") - .Then(x => x.ThenTheArgumentsArePassedInProperlyAndStoredOnTheSameObjectInstance("1", 2)) - .BDDfy(); - } - - [Fact] - public void PassingPublicStaticPrimitiveArguments() - { - this.Given(x => x.GivenPrimitiveInputs(string.Empty, 2), "Given inline input arguments {0} and {1}") - .Then(x => x.ThenTheArgumentsArePassedInProperlyAndStoredOnTheSameObjectInstance(string.Empty, 2)) - .BDDfy(); - } - - [Fact] - public void PassingPublicStaticPrimitivePropertyAsArguments() - { - this.Given(x => x.GivenPrimitiveInputs(SomeClassWithStaticMembers.StringProp, SomeClassWithStaticMembers.IntProp), "Given inline input arguments {0} and {1}") - .Then(x => x.ThenTheArgumentsArePassedInProperlyAndStoredOnTheSameObjectInstance(SomeClassWithStaticMembers.StringProp, SomeClassWithStaticMembers.IntProp)) - .BDDfy(); - } - - [Fact] - public void PassingNullPrimitiveArgumentInline() - { - this.Given(x => x.GivenPrimitiveInputs(null, 2), "Given inline input arguments {0} and {1}") - .Then(x => x.ThenTheArgumentsArePassedInProperlyAndStoredOnTheSameObjectInstance(null, 2)) - .BDDfy(); - } - - [Fact] - public void PassingPrimitiveArgumentsUsingVariables() - { - var input1 = "1"; - var input2 = 2; - - this.Given(x => x.GivenPrimitiveInputs(input1, input2), "Given input arguments {0} and {1} are passed in using varialbles") - .Then(x => x.ThenTheArgumentsArePassedInProperlyAndStoredOnTheSameObjectInstance(input1, input2)) - .BDDfy(); - } - - [Fact] - public void PassingNullAsPrimitiveArgumentsUsingVariables() - { - string input1 = null; - var input2 = 2; - - this.Given(x => x.GivenPrimitiveInputs(input1, input2), "Given input arguments {0} and {1} are passed in using varialbles") - .Then(x => x.ThenTheArgumentsArePassedInProperlyAndStoredOnTheSameObjectInstance(input1, input2)) - .BDDfy(); - } - - [Fact] - public void PassingPrimitiveArgumentsUsingFields() - { - this.Given(x => x.GivenPrimitiveInputs(_primitiveInput1Field, _primitiveInput2Field), "Given input arguments {0} and {1} are passed in using fields") - .Then(x => x.ThenTheArgumentsArePassedInProperlyAndStoredOnTheSameObjectInstance("1", 2)) - .BDDfy(); - } - - [Fact] - public void PassingPrimitiveArgumentsUsingProperties() - { - this.Given(x => x.GivenPrimitiveInputs(PrimitiveInput1Property, PrimitiveInput2Property), "Given input arguments {0} and {1} are passed in using properties") - .Then(x => x.ThenTheArgumentsArePassedInProperlyAndStoredOnTheSameObjectInstance("1", 2)) - .BDDfy(); - } - - [Fact] - public void PassingEnumArgumentInline() - { - this.Given(x => x.GivenEnumInputs(SomeEnumForTesting.Value1), "Given inline enum argument {0}") - .Then(x => x.ThenEnumArgumentIsPassedInProperlyAndStoredOnTheSameObjectInstance(SomeEnumForTesting.Value1)) - .BDDfy(); - } - - [Fact] - public void PassingEnumArgumentUsingVariable() - { - var someEnumForTesting = SomeEnumForTesting.Value1; - this.Given(x => x.GivenEnumInputs(someEnumForTesting), "Given enum argument {0} provided using variable") - .Then(x => x.ThenEnumArgumentIsPassedInProperlyAndStoredOnTheSameObjectInstance(someEnumForTesting)) - .BDDfy(); - } - - [Fact] - public void PassingEnumArgumentUsingFields() - { - this.Given(x => x.GivenEnumInputs(_enumInputField), "Given enum argument {0} provided using fields") - .Then(x => x.ThenEnumArgumentIsPassedInProperlyAndStoredOnTheSameObjectInstance(_enumInputField)) - .BDDfy(); - } - - [Fact] - public void PassingArrayArgumentsInline() - { - this.Given(x => x.GivenArrayInputs(new[] { "1", "2" }, new[] { 3, 4 }), "Given inline array input arguments") - .Then(x => x.ThenTheArgumentsArePassedInProperlyAndStoredOnTheSameObjectInstance(new[] { "1", "2" }, new[] { 3, 4 })) - .BDDfy(); - } - - [Fact] - public void PassingEnumerableArguments() - { - this.Given(x => x.GivenEnumerableInputs(EnumerableString, EnumerableInt), "Given enumerable input arguments") - .Then(x => x.ThenTheArgumentsArePassedInProperlyAndStoredOnTheSameObjectInstance(EnumerableString, EnumerableInt)) - .BDDfy(); - } - - [Fact] - public void PassingNullArrayArgumentInline() - { - this.Given(x => x.GivenArrayInputs(new[] {"1", null, "2"}, new[] {1, 2}), "Given inline input arguments {0} and {1}") - .Then(x => x.ThenTheArgumentsArePassedInProperlyAndStoredOnTheSameObjectInstance(new[] { "1", null, "2" }, new[] { 1, 2 })) - .BDDfy(); - } - - [Fact] - public void PassingNullAsArrayArgumentInline() - { - this.Given(x => x.GivenArrayInputs(null, new[] {1, 2}), "Given inline input arguments {0} and {1}") - .Then(x => x.ThenTheArgumentsArePassedInProperlyAndStoredOnTheSameObjectInstance(null, new[] { 1, 2 })) - .BDDfy(); - } - - [Fact] - public void PassingArrayArgumentsUsingVariables() - { - var input1 = new[] {"1", "2"}; - var input2 = new[] {3, 4}; - - this.Given(x => x.GivenArrayInputs(input1, input2), "Given array input arguments {0} and {1} are passed in using variables") - .Then(x => x.ThenTheArgumentsArePassedInProperlyAndStoredOnTheSameObjectInstance(input1, input2)) - .BDDfy(); - } - - [Fact] - public void PassingNullAsOneOfArrayArgumentUsingVariables() - { - var input1 = new[] {null, "2"}; - var input2 = new[] {3, 4}; - - this.Given(x => x.GivenArrayInputs(input1, input2), "Given array input arguments {0} and {1} are passed in using variables") - .Then(x => x.ThenTheArgumentsArePassedInProperlyAndStoredOnTheSameObjectInstance(input1, input2)) - .BDDfy(); - } - - [Fact] - public void PassingArrayArgumentsUsingFields() - { - this.Given(x => x.GivenArrayInputs(_arrayInput1Field, _arrayInput2Field), "Given array input arguments {0} and {1} are passed in using fields") - .Then(x => x.ThenTheArgumentsArePassedInProperlyAndStoredOnTheSameObjectInstance(new[] { "1", "2" }, new[] { 3, 4 })) - .BDDfy(); - } - - [Fact] - public void PassingArrayArgumentsUsingProperties() - { - this.Given(x => x.GivenArrayInputs(ArrayInput1Property, ArrayInput2Property), "Given array input arguments {0} and {1} are passed in using properties") - .Then(x => x.ThenTheArgumentsArePassedInProperlyAndStoredOnTheSameObjectInstance(new[] { "1", "2" }, new[] { 3, 4 })) - .BDDfy(); - } - - [Fact] - public void WhenTitleIsNotProvidedItIsFetchedFromMethodName() - { - var story = - this.Given(x => x.GivenPrimitiveInputs("1", 2)) - .Then(x => x.ThenTheArgumentsArePassedInProperlyAndStoredOnTheSameObjectInstance("1", 2)) - .BDDfy(); - - var scenario = story.Scenarios.First(); - scenario.Title.ShouldBe(Configurator.Humanizer.Humanize(nameof(WhenTitleIsNotProvidedItIsFetchedFromMethodName))); - } - - [Fact] - public void WhenTitleIsProvidedItIsUsedAsIs() - { - const string dummyTitle = "some dummy title; blah blah $#^"; - var story = - this.Given(x => x.GivenPrimitiveInputs("1", 2)) - .Then(x => x.ThenTheArgumentsArePassedInProperlyAndStoredOnTheSameObjectInstance("1", 2)) - .BDDfy(dummyTitle); - - var scenario = story.Scenarios.First(); - scenario.Title.ShouldBe(dummyTitle); - } - - private static void ExceptionThrowingAction() - { - throw new InvalidDataException(); - } - - [Fact] - public void CanPassActionToFluentApi() - { - this.Given(x => x.GivenAnAction(ExceptionThrowingAction)) - .Then(x => x.ThenCallingTheActionThrows()) - .BDDfy(); - } - - [Fact] - public void CanPassActionAndTitleToFluentApi() - { - this.Given(x => x.GivenAnAction(ExceptionThrowingAction), "Given an action that throws AppliationException") - .Then(x => x.ThenCallingTheActionThrows(), "Then calling the action does throw that exception") - .BDDfy(); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/ComplexStepsTests.cs b/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/ComplexStepsTests.cs deleted file mode 100644 index e97b5c23..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/ComplexStepsTests.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.Linq; -using Shouldly; -using TestStack.BDDfy.Tests.Configuration; -using Xunit; - -namespace TestStack.BDDfy.Tests.Scanner.FluentScanner -{ - [Collection("ExclusiveAccessToConfigurator")] - public class ComplexStepsTests - { - private int count; - - [Fact] - public void ShouldBeAbleToChainComplexTestWithFluentApi() - { - this.Given(_ => count.ShouldBe(0, "count should start with 0")) - .When(() => count++.ShouldBe(0), "When I do something") - .Given(() => count++.ShouldBe(1), "Given I am doing things in different order") - .Then(() => count++.ShouldBe(2), "Then they should run in defined order") - .When(() => count++.ShouldBe(3), "When I have whens after thens things still work") - .And(() => count++.ShouldBe(4), "And we should still be able to use ands") - .BDDfy(); - } - - [Fact] - public void ShouldContinueExecutingThensButStopWhenNextNotAssertStepIsHit() - { - var testRun = new TestRunnerTests.ScenarioWithFailingThen() - .Given(x => x.PassingGiven()) - .When(x => x.PassingWhen()) - .Then(x => x.FailingThen()) - .And(x => x.PassingAndThen()) - .When(x => x.PassingWhen()) - .Then(x => x.FailingThen()) - .LazyBDDfy(); - - Should.Throw(() => testRun.Run()); - var scenario = testRun.Story.Scenarios.First(); - scenario.Result.ShouldBe(Result.Failed); - var steps = scenario.Steps; - - steps.Count.ShouldBe(6); - steps[0].Result.ShouldBe(Result.Passed); - steps[0].ExecutionOrder.ShouldBe(ExecutionOrder.SetupState); - steps[1].Result.ShouldBe(Result.Passed); - steps[1].ExecutionOrder.ShouldBe(ExecutionOrder.Transition); - steps[2].Result.ShouldBe(Result.Failed); - steps[2].ExecutionOrder.ShouldBe(ExecutionOrder.Assertion); - steps[3].Result.ShouldBe(Result.Passed); - steps[3].ExecutionOrder.ShouldBe(ExecutionOrder.ConsecutiveAssertion); - steps[4].Result.ShouldBe(Result.NotExecuted); - steps[4].ExecutionOrder.ShouldBe(ExecutionOrder.Transition); - steps[5].Result.ShouldBe(Result.NotExecuted); - steps[5].ExecutionOrder.ShouldBe(ExecutionOrder.Assertion); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/DoesNotConflictWithnSubstitute.cs b/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/DoesNotConflictWithnSubstitute.cs deleted file mode 100644 index 23a3e325..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/DoesNotConflictWithnSubstitute.cs +++ /dev/null @@ -1,36 +0,0 @@ -using NSubstitute; -using Xunit; - -namespace TestStack.BDDfy.Tests.Scanner.FluentScanner -{ - public class DoesNotConflictWithnSubstitute - { - private ITestContext _subsitute; - private ExampleTable _exampleTable; - - [Fact] - public void CanUseFluentApiWithNSubstitute() - { - this.Given(_ => GivenSomeStuff()) - .When(_ => WhenSomethingHappens()) - .Then(_ => ThenICanStillUseNSubsitute()) - .BDDfy(); - } - - private void ThenICanStillUseNSubsitute() - { - _subsitute.Received().Examples = _exampleTable; - } - - private void WhenSomethingHappens() - { - _exampleTable = new ExampleTable(); - _subsitute.Examples = _exampleTable; - } - - private void GivenSomeStuff() - { - _subsitute = Substitute.For(); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/ExpressionExtensionsTests.cs b/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/ExpressionExtensionsTests.cs deleted file mode 100644 index 988d7966..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/ExpressionExtensionsTests.cs +++ /dev/null @@ -1,317 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using NUnit.Framework; -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Tests.Scanner.FluentScanner -{ - public class BaseClass - { - protected int InheritedInput1 = 1; - protected string InheritedInput2 = "2"; - - protected int[] InheritedArrayInput1 - { - get - { - return new[] { 3, 4 }; - } - } - - protected string[] InheritedArrayInput2 - { - get - { - return new[] { "5", "6" }; - } - } - } - - public class ExpressionExtensionsTests : BaseClass - { - private class ContainerType - { - public int Target { get; set; } - - public string Target2 { get; set; } - - public ContainerType SubContainer { get; set; } - - public override string ToString() - { - return Target2; - } - } - - class ClassUnderTest - { - public void MethodWithoutArguments() - { - - } - - public void MethodWithInputs(int input1, string input2) - { - - } - - public void MethodWithArrayInputs(int[] input1, string[] input2) - { - - } - - public void MethodWithInputs(ContainerType subContainer) - { - - } - - public void MethodWithNullableArg(decimal? nullableInput) - { - - } - - public Bar Foo { get; set; } - - public class Bar - { - public void Baz() - { - } - } - } - - List GetArgumentValues(Expression> action, ClassUnderTest instance) - { - return action.ExtractArguments(instance).Select(o => o.Value).ToList(); - } - - List GetArguments(Expression> action, ClassUnderTest instance) - { - return action.ExtractArguments(instance).ToList(); - } - - int _input1 = 1; - string _input2 = "2"; - const string ConstInput2 = "2"; - - int[] _arrayInput1 = { 1, 2 }; - public string[] _arrayInput2 = { "3", "4" }; - - public int[] ArrayInput1 - { - get - { - return _arrayInput1; - } - } - - string[] ArrayInput2 - { - get - { - return _arrayInput2; - } - } - - int Input1 { get { return _input1; } } - - public string Input2 { get { return _input2; } } - - int GetInput1(int someInput) - { - return someInput + 10; - } - - string GetInput2(string someInput) - { - return someInput + " Input 2"; - } - - ContainerType container = new(); - - [Fact] - public void NoArguments() - { - var arguments = GetArgumentValues(x => x.MethodWithoutArguments(), new ClassUnderTest()); - arguments.Count.ShouldBe(0); - } - - void AssertReturnedArguments(List arguments, params object[] expectedArgs) - { - arguments.Count.ShouldBe(expectedArgs.Length); - for (int i = 0; i < expectedArgs.Length; i++) - { - arguments[i].ShouldBe(expectedArgs[i]); - } - } - - [Fact] - public void InputArgumentsPassedInline() - { - var arguments = GetArgumentValues(x => x.MethodWithInputs(1, "2"), new ClassUnderTest()); - AssertReturnedArguments(arguments, 1, "2"); - } - - [Fact] - public void InputArgumentsProvidedUsingVariables() - { - int input1 = 1; - const string input2 = "2"; - var arguments = GetArgumentValues(x => x.MethodWithInputs(input1, input2), new ClassUnderTest()); - AssertReturnedArguments(arguments, input1, input2); - } - - [Fact] - public void InputArgumentsProvidedUsingFields() - { - var arguments = GetArgumentValues(x => x.MethodWithInputs(_input1, ConstInput2), new ClassUnderTest()); - AssertReturnedArguments(arguments, _input1, ConstInput2); - } - - [Fact] - public void InputArgumentsProvidedWhenCastIsInvolved() - { - // For some reason default(decimal) will cause a different expression when passing to a nullable method than - // if we have input1 = 1m; No idea why... - var input1 = default(decimal); - var arguments = GetArguments(x => x.MethodWithNullableArg(input1), new ClassUnderTest()); - input1 = 1; - AssertReturnedArguments(arguments.Select(a => a.Value).ToList(), input1); - } - - [Fact] - public void InputArgWithImplicitCast() - { - int input1 = 1; - var arguments = GetArgumentValues(x => x.MethodWithNullableArg(input1), new ClassUnderTest()); - AssertReturnedArguments(arguments, input1); - } - - [Fact] - public void InputArgumentsProvidedUsingProperty() - { - var arguments = GetArgumentValues(x => x.MethodWithInputs(Input1, Input2), new ClassUnderTest()); - AssertReturnedArguments(arguments, Input1, Input2); - } - - [Fact] - public void InputArgumentsProvidedUsingInheritedFields() - { - var arguments = GetArgumentValues(x => x.MethodWithInputs(InheritedInput1, InheritedInput2), new ClassUnderTest()); - AssertReturnedArguments(arguments, InheritedInput1, InheritedInput2); - } - - [Fact] - public void InputArgumentsProvidedUsingMethodCallDoesNotThrow() - { - Should.NotThrow(() => GetArgumentValues(x => x.MethodWithInputs(GetInput1(10), GetInput2("Test")), new ClassUnderTest())); - } - - [Fact] - public void ArrayInputsArgumentsProvidedInline() - { - var arguments = GetArgumentValues(x => x.MethodWithArrayInputs(new[] { 1, 2 }, new[] { "3", "4" }), new ClassUnderTest()); - AssertReturnedArguments(arguments, new[] { 1, 2 }, new[] { "3", "4" }); - } - - [Fact] - public void ArrayInputArgumentsProvidedUsingVariables() - { - var input1 = new[] { 1, 2 }; - var input2 = new[] { "3", "4" }; - var arguments = GetArgumentValues(x => x.MethodWithArrayInputs(input1, input2), new ClassUnderTest()); - AssertReturnedArguments(arguments, input1, input2); - } - - [Fact] - public void ArrayInputArgumentsProvidedUsingFields() - { - var arguments = GetArgumentValues(x => x.MethodWithArrayInputs(_arrayInput1, _arrayInput2), new ClassUnderTest()); - AssertReturnedArguments(arguments, _arrayInput1, _arrayInput2); - } - - [Fact] - public void ArrayInputArgumentsProvidedUsingProperty() - { - var arguments = GetArgumentValues(x => x.MethodWithArrayInputs(ArrayInput1, ArrayInput2), new ClassUnderTest()); - AssertReturnedArguments(arguments, ArrayInput1, ArrayInput2); - } - - [Fact] - public void ComplexArgument() - { - container.Target = 1; - container.SubContainer = new ContainerType { Target2 = "Foo" }; - - var arguments = GetArgumentValues(x => x.MethodWithInputs(container.Target, container.SubContainer.Target2), new ClassUnderTest()); - AssertReturnedArguments(arguments, 1, "Foo"); - } - - [Fact] - public void ComplexArgumentMethodCall() - { - container.Target = 1; - container.SubContainer = new ContainerType { Target2 = "Foo" }; - - var arguments = GetArgumentValues(x => x.MethodWithInputs(container.Target, container.SubContainer.ToString()), new ClassUnderTest()); - AssertReturnedArguments(arguments, 1, "Foo"); - } - - [Fact] - public void ComplexArgument2() - { - container.SubContainer = new ContainerType { Target2 = "Foo" }; - - var arguments = GetArgumentValues(x => x.MethodWithInputs(container.SubContainer), new ClassUnderTest()); - AssertReturnedArguments(arguments, container.SubContainer); - } - - [Fact] - public void ComplexArgumentWhenContainerIsNull() - { - ContainerType nullContainer = null; - var arguments = GetArgumentValues(x => x.MethodWithInputs(nullContainer.SubContainer), new ClassUnderTest()); - AssertReturnedArguments(arguments, new object[] { null }); - } - - [Fact] - public void MethodCallValue() - { - var arguments = GetArgumentValues(x => x.MethodWithInputs(GetNumberThree(), GetFooString()), new ClassUnderTest()); - AssertReturnedArguments(arguments, new object[] { 3, "Foo" }); - } - - [Fact] - public void DeepPropertyCall() - { - var arguments = GetArgumentValues(x => x.Foo.Baz(), new ClassUnderTest()); - arguments.ShouldBeEmpty(); - } - - private string GetFooString() - { - return "Foo"; - } - - private int GetNumberThree() - { - return 3; - } - - [Fact] - public void ArrayInputArgumentsProvidedUsingInheritedProperty() - { - var arguments = GetArgumentValues(x => x.MethodWithArrayInputs(InheritedArrayInput1, InheritedArrayInput2), new ClassUnderTest()); - AssertReturnedArguments(arguments, InheritedArrayInput1, InheritedArrayInput2); - } - - [Fact] - public void StaticField() - { - Should.NotThrow(() => GetArgumentValues(x => x.MethodWithInputs(GetInput1(10), GetInput2(string.Empty)), new ClassUnderTest())); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/InlineAssertions.cs b/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/InlineAssertions.cs deleted file mode 100644 index a3a434ca..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/InlineAssertions.cs +++ /dev/null @@ -1,49 +0,0 @@ -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Tests.Scanner.FluentScanner -{ - public class InlineAssertions - { - private int _x, _y, _z; - - [Fact] - public void CanUseInlineAssertions() - { - this.Given(() => { _x = 0; _y = 2; }, "Given x equals 0") - .When(() => { _z = _x*_y; }, "When x and y are multiplied") - .Then(() => _z.ShouldBe(0), "Then the result is 0") - .BDDfy(); - } - - [Fact] - public void CanUseTitleOnlySteps() - { - this.Given("Given x equals 0") - .And("and y equals 0") - .When("When x and y are multiplied") - .And("and set to z") - .Then("Then z equals 0") - .And("and we're all cool") - .BDDfy(); - } - - [Fact] - public void CanMixThemAllIn() - { - this.Given(() => { _x = 0; _y = 2; }, "Given x equals 0") - .And("and y equals 0") - .When(_ => WhenXAndYAreMultiplied()) - .And("and set to z") - .Then(() => _z.ShouldBe(0), "Then the result is 0") - .And("and we're all cool") - .BDDfy(); - - } - - void WhenXAndYAreMultiplied() - { - _z = _x*_y; - } - } -} diff --git a/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/PrependStepTypeTests.VerifyPrependStepTitles.approved.txt b/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/PrependStepTypeTests.VerifyPrependStepTitles.approved.txt deleted file mode 100644 index 66db3950..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/PrependStepTypeTests.VerifyPrependStepTitles.approved.txt +++ /dev/null @@ -1,13 +0,0 @@ - -Scenario: Verify prepend step titles - Given a step with given in it - Given a step without given in it - And given a step with and given in it - And a step without given in it - But in step - But nothing in step - When stuff - When stuff - Then we are winning - Then we are winning - diff --git a/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/PrependStepTypeTests.cs b/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/PrependStepTypeTests.cs deleted file mode 100644 index 2b640dde..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/PrependStepTypeTests.cs +++ /dev/null @@ -1,78 +0,0 @@ -#if Approvals -using System.Runtime.CompilerServices; -using Shouldly; -using TestStack.BDDfy.Reporters; -using Xunit; - -namespace TestStack.BDDfy.Tests.Scanner.FluentScanner -{ - public class PrependStepTypeTests - { - [Fact] - [MethodImpl(MethodImplOptions.NoInlining)] - public void VerifyPrependStepTitles() - { - var story = this.Given(_ => GivenAStepWithGivenInIt()) - .Given(_ => AStepWithoutGivenInIt()) - .And(_ => AndGivenAStepWithAndGivenInIt()) - .And(_ => AStepWithoutGivenInIt()) - .But(_ => ButInStep()) - .But(_ => NothingInStep()) - .When(_ => WhenStuff()) - .When(_ => Stuff()) - .Then(_ => ThenWeAreWinning()) - .Then(_ => WeAreWinning()) - .BDDfy(); - - var textReporter = new TextReporter(); - textReporter.Process(story); - textReporter.ToString().ShouldMatchApproved(); - } - - private void GivenAStepWithGivenInIt() - { - - } - - private void AndGivenAStepWithAndGivenInIt() - { - - } - - private void AStepWithoutGivenInIt() - { - - } - - private void ButInStep() - { - - } - - private void NothingInStep() - { - - } - - private void WhenStuff() - { - - } - - private void Stuff() - { - - } - - private void ThenWeAreWinning() - { - - } - - private void WeAreWinning() - { - - } - } -} -#endif \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/ScenarioToBeScannedUsingFluentScanner.cs b/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/ScenarioToBeScannedUsingFluentScanner.cs deleted file mode 100644 index c7ee3db8..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/ScenarioToBeScannedUsingFluentScanner.cs +++ /dev/null @@ -1,93 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; - -namespace TestStack.BDDfy.Tests.Scanner.FluentScanner -{ - [Story] - class ScenarioToBeScannedUsingFluentScanner - { - internal const string InputDateStepTitleTemplate = "The provided date is {0:MMM d yyyy}"; - public static readonly DateTime InputDate = DateTime.Parse("2011-10-20", new CultureInfo("en-AU")); - - private string[] _input1; - private int[] _input2; - private int _input3; - - public int Input3 - { - get { return _input3; } - } - - public int[] Input2 - { - get { return _input2; } - } - - public string[] Input1 - { - get { return _input1; } - } - - public void GivenSomeState(int input1, int input2) - { - } - - public void WhenSomeStepUsesIncompatibleNamingConvention() - { - } - - public void AndAMethodTakesArrayInputs(string[] input1, int[] input2, int input3) - { - _input1 = input1; - _input2 = input2; - _input3 = input3; - } - - [Then] - public void AndSomeStateWithIncorrectAttribute() - { } - - public void WhenSomethingHappens(string input1) - { - } - - public void AndThenSomethingElseHappens() - { - } - - public void ThenTitleFormatingWorksToo(DateTime date) - { - } - - public void ThenTheFollowingAssertionsShouldBeCorrect() - { } - - [When] - public void AndIncorrectAttributeWouldNotMatter() - { } - - public void Dispose() - {} - - public static IEnumerable GetSteps(ScenarioToBeScannedUsingFluentScanner testObject) - { - var fluentScanner = TestContext.GetContext(testObject - .Given(s => s.GivenSomeState(1, 2)) - .And(s => s.WhenSomeStepUsesIncompatibleNamingConvention()) - .And(s => s.AndAMethodTakesArrayInputs(new[] {"1", "2"}, new[] {3, 4}, 5)) - .And(s => s.AndSomeStateWithIncorrectAttribute()) - .When(s => s.WhenSomethingHappens("some input here")) - .And(s => s.AndThenSomethingElseHappens(), "Overriding step name without arguments") - .And(s => s.WhenSomethingHappens("other input"), "step used with {0} for the second time") - .And(s => s.WhenSomethingHappens("other input"), false) - .Then(s => s.ThenTheFollowingAssertionsShouldBeCorrect()) - .And(s => s.AndIncorrectAttributeWouldNotMatter()) - .And(s => s.ThenTitleFormatingWorksToo(InputDate), InputDateStepTitleTemplate) - .TearDownWith(s => s.Dispose())).FluentScanner; - - return fluentScanner.GetScanner(null, null).Scan().Scenarios.SelectMany(s => s.Steps).ToList(); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/StepTitleTests.cs b/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/StepTitleTests.cs deleted file mode 100644 index cd637327..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/StepTitleTests.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System.Linq; -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Tests.Scanner.FluentScanner -{ - public class StepTitleTests - { - private string _mutatedState; - - [Fact] - public void MethodCallInStepTitle() - { - FooClass something = new(); - var story = this - .Given(_ => GivenWeMutateSomeState()) - .When(_ => something.Sub.SomethingHappens()) - .And(_ => something.Sub.SomethingWithDifferentTitle()) - .Then(_ => ThenTitleHas(AMethodCall())) - .And(_ => something.Sub.SomethingWithArg("foo")) - .And(_ => something.Sub.SomethingWithArg2("foo")) - .And(_ => something.Sub.SomethingWithArg3("foo")) - .BDDfy(); - - story.Scenarios.Single().Steps.ElementAt(2).Title.ShouldBe("And different title"); - story.Scenarios.Single().Steps.ElementAt(3).Title.ShouldBe("Then title has Mutated state"); - story.Scenarios.Single().Steps.ElementAt(4).Title.ShouldBe("And with arg foo"); - story.Scenarios.Single().Steps.ElementAt(5).Title.ShouldBe("And with arg"); - story.Scenarios.Single().Steps.ElementAt(6).Title.ShouldBe("And with foo arg"); - } - - public class FooClass - { - public FooClass() - { - Sub = new BarClass(); - } - - public BarClass Sub { get; set; } - } - - public class BarClass - { - public void SomethingHappens() - { - - } - - [StepTitle("Different title")] - public void SomethingWithDifferentTitle() - { - } - - [StepTitle("With arg")] - public void SomethingWithArg(string arg) - { - } - - [StepTitle("With arg", false)] - public void SomethingWithArg2(string arg) - { - } - - [StepTitle("With {0} arg", false)] - public void SomethingWithArg3(string arg) - { - } - } - - private string AMethodCall() - { - return _mutatedState; - } - - private void GivenWeMutateSomeState() - { - _mutatedState = "Mutated state"; - } - - private void ThenTitleHas(string result) - { - result.ShouldBe(_mutatedState); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/WhenStepsAreScannedUsingFluentScanner.cs b/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/WhenStepsAreScannedUsingFluentScanner.cs deleted file mode 100644 index 1123d70e..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/FluentScanner/WhenStepsAreScannedUsingFluentScanner.cs +++ /dev/null @@ -1,302 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Tests.Scanner.FluentScanner -{ - public class WhenStepsAreScannedUsingFluentScanner - { - private IEnumerable _steps; - - public WhenStepsAreScannedUsingFluentScanner() - { - var scenario = new ScenarioToBeScannedUsingFluentScanner(); - _steps = ScenarioToBeScannedUsingFluentScanner.GetSteps(scenario); - } - - [Fact] - public void IndicatedStepsAreReturned() - { - _steps.Count().ShouldBe(12); - } - - Step GivenSomeStateStep - { - get - { - return _steps.Single(s => s.Title == "Given some state 1, 2"); - } - } - - [Fact] - public void GivenSomeState_StepIsASetupMethod() - { - GivenSomeStateStep.ExecutionOrder.ShouldBe(ExecutionOrder.SetupState); - } - - [Fact] - public void GivenSomeState_IsNotAsserting() - { - GivenSomeStateStep.Asserts.ShouldBe(false); - } - - [Fact] - public void GivenSomeState_StepReports() - { - GivenSomeStateStep.ShouldReport.ShouldBe(true); - } - - Step WhenSomeStepUsesIncompatibleNamingConventionStep - { - get - { - return _steps.Single(s => s.Title.Trim() == "And when some step uses incompatible naming convention"); - } - } - - [Fact] - public void WhenSomeStepUsesIncompatibleNamingConvention_IsAConsecutiveSetupMethod() - { - WhenSomeStepUsesIncompatibleNamingConventionStep.ExecutionOrder.ShouldBe(ExecutionOrder.ConsecutiveSetupState); - } - - [Fact] - public void WhenSomeStepUsesIncompatibleNamingConvention_DoesNotAssert() - { - WhenSomeStepUsesIncompatibleNamingConventionStep.Asserts.ShouldBe(false); - } - - [Fact] - public void WhenSomeStepUsesIncompatibleNamingConvention_Reports() - { - WhenSomeStepUsesIncompatibleNamingConventionStep.ShouldReport.ShouldBe(true); - } - - Step AndAMethodTakesArrayInputsStep - { - get - { - return _steps.Single(s => s.Title.Trim() == "And a method takes array inputs 1, 2, 3, 4, 5"); - } - } - - [Fact] - public void AndAMethodTakesArrayInputs_IsAConsecutiveSetupMethod() - { - AndAMethodTakesArrayInputsStep.ExecutionOrder.ShouldBe(ExecutionOrder.ConsecutiveSetupState); - } - - [Fact] - public void AndAMethodTakesArrayInputs_DoesNotAssert() - { - AndAMethodTakesArrayInputsStep.Asserts.ShouldBe(false); - } - - [Fact] - public void AndAMethodTakesArrayInputs_Reports() - { - AndAMethodTakesArrayInputsStep.ShouldReport.ShouldBe(true); - } - - Step WhenSomethingHappensTransitionStep - { - get - { - return _steps.Single(s => s.Title == "When something happens some input here"); - } - } - - [Fact] - public void WhenSomethingHappensTransitionStep_IsATransitionStep() - { - WhenSomethingHappensTransitionStep.ExecutionOrder.ShouldBe(ExecutionOrder.Transition); - } - - [Fact] - public void WhenSomethingHappensTransitionStep_DoesNotAssert() - { - WhenSomethingHappensTransitionStep.Asserts.ShouldBe(false); - } - - [Fact] - public void WhenSomethingHappensTransitionStep_Reports() - { - WhenSomethingHappensTransitionStep.ShouldReport.ShouldBe(true); - } - - Step WhenSomethingHappensTransitionStepIgnoringInputInStepTitle - { - get - { - return _steps.Single(s => s.Title == "And when something happens"); - } - } - - [Fact] - public void WhenSomethingHappensTransitionStepIgnoringInputInStepTitle_IsAConsecutiveTransitionStep() - { - WhenSomethingHappensTransitionStepIgnoringInputInStepTitle.ExecutionOrder.ShouldBe(ExecutionOrder.ConsecutiveTransition); - } - - [Fact] - public void WhenSomethingHappensTransitionStepIgnoringInputInStepTitle_DoesNotAssert() - { - WhenSomethingHappensTransitionStepIgnoringInputInStepTitle.Asserts.ShouldBe(false); - } - - [Fact] - public void WhenSomethingHappensTransitionStepIgnoringInputInStepTitle_Reports() - { - WhenSomethingHappensTransitionStepIgnoringInputInStepTitle.ShouldReport.ShouldBe(true); - } - - Step WhenSomethingHappensConsecutiveTransitionStep - { - get - { - return _steps.Single(s => s.Title.Trim() == "step used with other input for the second time"); - } - } - - [Fact] - public void WhenSomethingHappensConsecutiveTransitionStep_IsAConsecutiveTransitionStep() - { - WhenSomethingHappensConsecutiveTransitionStep.ExecutionOrder.ShouldBe(ExecutionOrder.ConsecutiveTransition); - } - - [Fact] - public void WhenSomethingHappensConsecutiveTransitionStep_DoesNotAssert() - { - WhenSomethingHappensConsecutiveTransitionStep.Asserts.ShouldBe(false); - } - - [Fact] - public void WhenSomethingHappensConsecutiveTransitionStep_Reports() - { - WhenSomethingHappensConsecutiveTransitionStep.ShouldReport.ShouldBe(true); - } - - Step AndThenSomethingElseHappensStep - { - get - { - return _steps.Single(s => s.Title.Trim() == "Overriding step name without arguments"); - } - } - - [Fact] - public void AndThenSomethingElseHappensStep_IsAConsecutiveTransitionStep() - { - AndThenSomethingElseHappensStep.ExecutionOrder.ShouldBe(ExecutionOrder.ConsecutiveTransition); - } - - [Fact] - public void AndThenSomethingElseHappensStep_DoesNotAssert() - { - AndThenSomethingElseHappensStep.Asserts.ShouldBe(false); - } - - [Fact] - public void AndThenSomethingElseHappensStep_Reports() - { - AndThenSomethingElseHappensStep.ShouldReport.ShouldBe(true); - } - - Step ThenTheFollowingAssertionsShouldBeCorrectStep - { - get - { - return _steps.Single(s => s.Title == "Then the following assertions should be correct"); - } - } - - [Fact] - public void ThenTheFollowingAssertionsShouldBeCorrectStep_IsAnAssertingStep() - { - ThenTheFollowingAssertionsShouldBeCorrectStep.ExecutionOrder.ShouldBe(ExecutionOrder.Assertion); - } - - [Fact] - public void ThenTheFollowingAssertionsShouldBeCorrectStep_DoesAssert() - { - ThenTheFollowingAssertionsShouldBeCorrectStep.Asserts.ShouldBe(true); - } - - [Fact] - public void ThenTheFollowingAssertionsShouldBeCorrectStep_Reports() - { - ThenTheFollowingAssertionsShouldBeCorrectStep.ShouldReport.ShouldBe(true); - } - - Step AndIncorrectAttributeWouldNotMatterStep - { - get - { - return _steps.Single(s => s.Title.Trim() == "And incorrect attribute would not matter"); - } - } - - [Fact] - public void AndIncorrectAttributeWouldNotMatterStep_IsAConsecutiveAssertingStep() - { - AndIncorrectAttributeWouldNotMatterStep.ExecutionOrder.ShouldBe(ExecutionOrder.ConsecutiveAssertion); - } - - [Fact] - public void AndIncorrectAttributeWouldNotMatterStep_DoesAssert() - { - AndIncorrectAttributeWouldNotMatterStep.Asserts.ShouldBe(true); - } - - [Fact] - public void AndIncorrectAttributeWouldNotMatterStep_Reports() - { - AndIncorrectAttributeWouldNotMatterStep.ShouldReport.ShouldBe(true); - } - - Step AndInputsAreFormattedPropertlyInTheTitle - { - get - { - var formattedTitle = string.Format( - ScenarioToBeScannedUsingFluentScanner.InputDateStepTitleTemplate, - ScenarioToBeScannedUsingFluentScanner.InputDate); - - return _steps.Single(s => s.Title.Trim() == formattedTitle); - } - } - - [Fact] - public void AndInputsAreFormattedPropertlyInTheTitle_IsAConsecutiveAssertingStep() - { - AndInputsAreFormattedPropertlyInTheTitle.ExecutionOrder.ShouldBe(ExecutionOrder.ConsecutiveAssertion); - } - - Step TearDownStep - { - get - { - return _steps.Single(s => s.Title == "Dispose"); - } - } - - [Fact] - public void TearDownStep_IsAConsecutiveAssertingStep() - { - TearDownStep.ExecutionOrder.ShouldBe(ExecutionOrder.TearDown); - } - - [Fact] - public void TearDownStep_DoesAssert() - { - TearDownStep.Asserts.ShouldBe(false); - } - - [Fact] - public void TearDownStep_DoesNotReports() - { - TearDownStep.ShouldReport.ShouldBe(false); - } - } -} diff --git a/src/TestStack.BDDfy.Tests/Scanner/ReflectiveScanner/DefaultScanForStepsByMethodNameTests.cs b/src/TestStack.BDDfy.Tests/Scanner/ReflectiveScanner/DefaultScanForStepsByMethodNameTests.cs deleted file mode 100644 index 02579cad..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/ReflectiveScanner/DefaultScanForStepsByMethodNameTests.cs +++ /dev/null @@ -1,105 +0,0 @@ -using System.Linq; -using NUnit.Framework; -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Tests.Scanner.ReflectiveScanner -{ - public class DefaultScanForStepsByMethodNameTests - { - class ScenarioWithVaryingStepTexts - { - public void GivenThePascalCaseForMethodName() { } - public void When_Step_Name_Uses_Underscore_With_Pascal_Case() { } - public void Then_with_lower_case_underscored_method_name() { } - - [RunStepWithArgs(1, 2, 3)] - [RunStepWithArgs(3, 4, 5)] - public void WhenStepIsRunWithArgumentsWithoutProvidedText(int input1, int input2, int input3) { } - - [RunStepWithArgs(new[] {1, 2, 3, 4, 5})] - public void WhenStepIsRunWithArrayArgumentsWithoutProvidedText(int[] input) { } - - [RunStepWithArgs(new[] {1, 2, 3, 4, 5}, StepTextTemplate = "With the following inputs {0}")] - public void WhenStepIsRunWithArrayArgumentsWithProvidedText(int[] input) { } - - [RunStepWithArgs("input string")] - public void WhenSomeStringIsProvidedAsInput(string input) { } - - [RunStepWithArgs(1, 2, 3, StepTextTemplate = "The step text gets argument {0}, {1} and then {2}")] - [RunStepWithArgs(3, 4, 5, StepTextTemplate = "The step text gets argument {0}, {1} and then {2}")] - public void WhenStepIsRunWithArgumentsWithProvidedText(int input1, int input2, int input3) { } - - public void WhenStepNameEndsWithNumber29() - { - } - } - - static void VerifyMethod(string expectedStepTitle, bool exists = true) - { - var testObject = new ScenarioWithVaryingStepTexts(); - var scanner = new DefaultMethodNameStepScanner(); - var steps = scanner.Scan(TestContext.GetContext(testObject)).ToList(); - var theStep = steps.Where(s => s.Title == expectedStepTitle); - - theStep.Count().ShouldBe(exists ? 1 : 0); - } - - [Fact] - public void TheMethodWithPascalCaseIsSeparatedAndTurnedIntoLowerCaseExceptTheFirstWord() - { - VerifyMethod("Given the pascal case for method name"); - } - - [Fact] - public void TheMethodWithUnderscoreAndLowerCaseWordsIsSeparatedAndCaseIsRetained() - { - VerifyMethod("Then with lower case underscored method name"); - } - - [Fact] - public void TrailingNumberGetsTheSameTreatmentAsWords() - { - VerifyMethod("When step name ends with number 29"); - } - - [Fact] - public void TheMethodWithArgumentWithoutProvidedTextGetsArgumentsAppendedToTheMethodName() - { - VerifyMethod("When step is run with arguments without provided text 1, 2, 3"); - VerifyMethod("When step is run with arguments without provided text 3, 4, 5"); - } - - [Fact] - public void TheMethodWithArrayArgumentWithoutProvidedTextGetsArgumentsAppendedToTheMethodName() - { - VerifyMethod("When step is run with array arguments without provided text 1, 2, 3, 4, 5"); - } - - [Fact] - public void TheMethodWithArrayArgumentWithProvidedTextUsesArrayToFormatTheTextTemplate() - { - VerifyMethod("With the following inputs 1, 2, 3, 4, 5"); - } - - [Fact] - public void TheMethodIsRunWithStringAsProvidedArgumentsWithoutProvidedTextTemplate() - { - VerifyMethod("When some string is provided as input input string"); - } - - [Fact] - public void TheMethodWithArgumentWithProvidedTextUsesTheProvidedTextAsTemplate() - { - VerifyMethod("The step text gets argument 1, 2 and then 3"); - VerifyMethod("The step text gets argument 3, 4 and then 5"); - } - - [Fact] - public void TheMethodWithArgumentWithProvidedTextDoesNotUseTheMethodName() - { - VerifyMethod("When step is run with arguments with provided text 1, 2, 3", false); - VerifyMethod("When step is run with arguments with provided text 3, 4, 5", false); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Scanner/ReflectiveScanner/ExecutableAttributeOrderOrdersTheStepsCorrectly.cs b/src/TestStack.BDDfy.Tests/Scanner/ReflectiveScanner/ExecutableAttributeOrderOrdersTheStepsCorrectly.cs deleted file mode 100644 index a3f45317..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/ReflectiveScanner/ExecutableAttributeOrderOrdersTheStepsCorrectly.cs +++ /dev/null @@ -1,196 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Shouldly; -using TestStack.BDDfy.Configuration; -using Xunit; - -namespace TestStack.BDDfy.Tests.Scanner.ReflectiveScanner -{ - public class ExecutableAttributeOrderOrdersTheStepsCorrectly - { - private List _steps; - - private class TypeWithOrderedAttribute - { - [AndThen(Order = 2)] - public void AndThen2() { } - - [AndThen(Order = -3)] - public void AndThenNeg3() { } - - [AndThen] - public void AndThen0() { } - - [AndThen(Order = 2)] - public void AndThen2Again() { } - - [Then(Order = 1)] - public void Then1() { } - - [Then(Order = 3)] - public void Then3() { } - - [Given(Order = 1)] - public void Given1() { } - - [Given(Order = 3)] - public void Given3() { } - - [AndGiven] - public void AndGiven0() { } - - [AndGiven(Order = 2)] - public void AndGiven2() { } - - [AndGiven(Order = -3)] - public void AndGivenNeg3() { } - - [AndGiven(Order = 2)] - public void AndGiven2Again() { } - - [When(Order = 1)] - public void When1() { } - - [When(Order = 3)] - public void When3() { } - - [AndWhen(Order = 2)] - public void AndWhen2() { } - - [AndWhen(Order = -3)] - public void AndWhenNeg3() { } - - [AndWhen] - public void AndWhen0() { } - - [AndWhen(Order = 2)] - public void AndWhen2Again() { } - - } - - public ExecutableAttributeOrderOrdersTheStepsCorrectly() - { - var testObject = new TypeWithOrderedAttribute(); - var stepScanners = Configurator.Scanners.GetStepScanners(testObject).ToArray(); - var scanner = new ReflectiveScenarioScanner(stepScanners); - var scenario = scanner.Scan(TestContext.GetContext(testObject)).First(); - _steps = scenario.Steps; - } - - [Fact] - public void Step0IsGiven1() - { - _steps[0].Title.ShouldBe("Given 1"); - } - - [Fact] - public void Step1IsGiven3() - { - _steps[1].Title.ShouldBe("Given 3"); - } - - - [Fact] - public void Step2IsAndGivenNeg3() - { - _steps[2].Title.ShouldBe("And given neg 3"); - } - - [Fact] - public void Step3IsAndGiven0() - { - _steps[3].Title.ShouldBe("And given 0"); - } - - - [Fact] - public void Step4AndGiven2() - { - _steps[4].Title.ShouldBe("And given 2"); - } - - [Fact] - public void Step5AndGiven2Again() - { - _steps[5].Title.ShouldBe("And given 2 again"); - } - - - [Fact] - public void Step6IsWhen1() - { - _steps[6].Title.ShouldBe("When 1"); - } - - [Fact] - public void Step7IsWhen3() - { - _steps[7].Title.ShouldBe("When 3"); - } - - - [Fact] - public void Step8IsAndWhenNeg3() - { - _steps[8].Title.ShouldBe("And when neg 3"); - } - - [Fact] - public void Step9IsAndWhen0() - { - _steps[9].Title.ShouldBe("And when 0"); - } - - - [Fact] - public void Step10AndWhen2() - { - _steps[10].Title.ShouldBe("And when 2"); - } - - [Fact] - public void Step11AndWhen2Again() - { - _steps[11].Title.ShouldBe("And when 2 again"); - } - - - [Fact] - public void Step12IsThen1() - { - _steps[12].Title.ShouldBe("Then 1"); - } - - [Fact] - public void Step13IsThen3() - { - _steps[13].Title.ShouldBe("Then 3"); - } - - - [Fact] - public void Step14IsAndThenNeg3() - { - _steps[14].Title.ShouldBe("And then neg 3"); - } - - [Fact] - public void Step15IsAndThen0() - { - _steps[15].Title.ShouldBe("And then 0"); - } - - - [Fact] - public void Step16AndThen2() - { - _steps[16].Title.ShouldBe("And then 2"); - } - - [Fact] - public void Step17AndThen2Again() - { - _steps[17].Title.ShouldBe("And then 2 again"); - } - } -} diff --git a/src/TestStack.BDDfy.Tests/Scanner/ReflectiveScanner/ExecutableAttributeScannerTests.cs b/src/TestStack.BDDfy.Tests/Scanner/ReflectiveScanner/ExecutableAttributeScannerTests.cs deleted file mode 100644 index 2d5b6481..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/ReflectiveScanner/ExecutableAttributeScannerTests.cs +++ /dev/null @@ -1,137 +0,0 @@ -using System.Linq; -using NUnit.Framework; -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Tests.Scanner.ReflectiveScanner -{ - public class ExecutableAttributeScannerTests - { - class ScenarioWithVaryingStepTexts - { - [Given] - public void ThePascalCaseForMethodName() { } - - [Then] - public void with_lower_case_underscored_method_name() { } - - [Given] - [RunStepWithArgs(1, 2, 3)] - [RunStepWithArgs(3, 4, 5)] - public void StepIsRunWithArgumentsWithoutProvidedText(int input1, int input2, int input3) { } - - [Given] - [RunStepWithArgs(1, 2, 3, StepTextTemplate = "The step text gets argument {0}, {1} and then {2}")] - [RunStepWithArgs(3, 4, 5, StepTextTemplate = "The step text gets argument {0}, {1} and then {2}")] - public void StepIsRunWithArgumentsWithProvidedText(int input1, int input2, int input3) { } - - [When] - [RunStepWithArgs(new[] { 1, 2, 3, 4, 5 })] - public void WhenStepIsRunWithArrayArgumentsWithoutProvidedText(int[] input) { } - - [When] - [RunStepWithArgs(new[] { 1, 2, 3, 4, 5 }, StepTextTemplate = "With the following inputs {0}")] - public void WhenStepIsRunWithArrayArgumentsWithProvidedText(int[] input) { } - - [When(StepTitle = "Running step with arg {0}, {1} and {2} using exec attribute template")] - [RunStepWithArgs(1, 2, 3)] - public void RunningStepWithArgsUsingExecAttributeTemplate(int input1, int input2, int input3){} - - [When(StepTitle = "Running step with arg {0}, {1} and {2} when template is provided by exec attribute and RunStepWithArgs attribute")] - [RunStepWithArgs(1, 2, 3)] - [RunStepWithArgs(4, 5, 6, StepTextTemplate = "The template provided on RunStepWithArgs overrides all the others {0}, {1}, {2}")] - public void RunningStepWithArgsUsingExecAttributeTemplateAndRunStepWithArgsTemplate(int input1, int input2, int input3){} - - [When("Running step with arg {0}, {1} and {2} using exec attribute(string stepTitle)")] - [RunStepWithArgs(1, 2, 3)] - public void RunningStepWithArgsUsingExecAttributeConstructorTemplate(int input1, int input2, int input3) { } - - [When("Running step with arg {0}, {1} and {2} when template is provided by exec attribute(string stepTitle) and RunStepWithArgs attribute")] - [RunStepWithArgs(1, 2, 3)] - [RunStepWithArgs(4, 5, 6, StepTextTemplate = "The template provided on RunStepWithArgs overrides all the others {0}, {1}, {2} attribute(string stepTitle)")] - public void RunningStepWithArgsUsingExecAttributeConstructorTemplateAndRunStepWithArgsTemplate(int input1, int input2, int input3) { } - } - - static void VerifyMethod(string expectedStepTitle, bool exists = true) - { - var scanner = new ExecutableAttributeStepScanner(); - var steps = scanner.Scan(TestContext.GetContext(new ScenarioWithVaryingStepTexts())).ToList(); - var theStep = steps.Where(s => s.Title == expectedStepTitle); - - theStep.Count().ShouldBe(exists ? 1 : 0); - } - - [Fact] - public void TheMethodWithPascalCaseIsSeparatedAndTurnedIntoLowerCaseExceptTheFirstWord() - { - VerifyMethod("The pascal case for method name"); - } - - [Fact] - public void TheMethodWithUnderscoreAndLowerCaseWordsIsSeparatedAndCaseIsRetained() - { - VerifyMethod("with lower case underscored method name"); - } - - [Fact] - public void TheMethodWithArrayArgumentWithoutProvidedTextGetsArgumentsAppendedToTheMethodName() - { - VerifyMethod("When step is run with array arguments without provided text 1, 2, 3, 4, 5"); - } - - [Fact] - public void TheMethodWithArrayArgumentWithProvidedTextUsesArrayToFormatTheTextTemplate() - { - VerifyMethod("With the following inputs 1, 2, 3, 4, 5"); - } - - [Fact] - public void TheMethodWithArgumentWithoutProvidedTextGetsArgumentsAppendedToTheMethodName() - { - VerifyMethod("Step is run with arguments without provided text 1, 2, 3"); - VerifyMethod("Step is run with arguments without provided text 3, 4, 5"); - } - - [Fact] - public void TheMethodWithArgumentWithProvidedTextUsesTheProvidedTextAsTemplate() - { - VerifyMethod("The step text gets argument 1, 2 and then 3"); - VerifyMethod("The step text gets argument 3, 4 and then 5"); - } - - [Fact] - public void TheMethodWithArgumentWithProvidedTextDoesNotUseTheMethodName() - { - VerifyMethod("Step is run with arguments with provided text 1, 2, 3", false); - VerifyMethod("Step is run with arguments with provided text 3, 4, 5", false); - } - - [Fact] - public void TheMethodWithArgumentWithTextProvidedOnTheExecutableAttributeUsesExecutableAttributeTemplate() - { - VerifyMethod("Running step with arg 1, 2 and 3 using exec attribute template"); - } - - [Fact] - public void RunStepWithArgsTemplateOverrideAllOtherTemplates() - { - VerifyMethod("Running step with arg 1, 2 and 3 when template is provided by exec attribute and RunStepWithArgs attribute"); - VerifyMethod("Running step with args using exec attribute template and run step with args template 1, 2, 3", false); - VerifyMethod("The template provided on RunStepWithArgs overrides all the others 4, 5, 6"); - } - - [Fact] - public void TheMethodWithArgumentWithTextProvidedOnTheExecutableAttributeConstructorUsesExecutableAttributeTemplate() - { - VerifyMethod("Running step with arg 1, 2 and 3 using exec attribute(string stepTitle)"); - } - - [Fact] - public void RunStepWithArgsTemplateOverrideAllOtherTemplatesThatUseTheConstructor() - { - VerifyMethod("Running step with arg 1, 2 and 3 when template is provided by exec attribute(string stepTitle) and RunStepWithArgs attribute"); - VerifyMethod("Running step with args using exec attribute template and run step with args template 1, 2, 3", false); - VerifyMethod("The template provided on RunStepWithArgs overrides all the others 4, 5, 6 attribute(string stepTitle)"); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Scanner/ReflectiveScanner/PropertiesAreNotConsideredAsStepsEvenWhenTheirNameMatchesConventions.cs b/src/TestStack.BDDfy.Tests/Scanner/ReflectiveScanner/PropertiesAreNotConsideredAsStepsEvenWhenTheirNameMatchesConventions.cs deleted file mode 100644 index 916e179c..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/ReflectiveScanner/PropertiesAreNotConsideredAsStepsEvenWhenTheirNameMatchesConventions.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using Xunit; - -namespace TestStack.BDDfy.Tests.Scanner.ReflectiveScanner -{ - public class PropertiesAreNotConsideredAsStepsEvenWhenTheirNameMatchesConventions - { - // It has to end with context to fulfil the convention; after compilation this property will be get_GivenblahblahContext - protected int GivenThePropertyNameFulfillsTheConventionsContext - { - get { throw new InvalidOperationException("This should not have been called"); } - set { throw new InvalidOperationException("This should not have been called"); } - } - - public int GivenThePublicPropertyNameFulfillsTheConventionsContext - { - get { throw new InvalidOperationException("This should not have been called"); } - set { throw new InvalidOperationException("This should not have been called"); } - } - - static int GivenTheStaticPropertyNameFulfillsTheConventionsContext - { - get { throw new InvalidOperationException("This should not have been called"); } - set { throw new InvalidOperationException("This should not have been called"); } - } - - void ThenThePropertyShouldBeAvoided() - { - } - - [Fact] - public void Execute() - { - this.BDDfy(); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Scanner/ReflectiveScanner/StepScannerExtensions.cs b/src/TestStack.BDDfy.Tests/Scanner/ReflectiveScanner/StepScannerExtensions.cs deleted file mode 100644 index 23ed5894..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/ReflectiveScanner/StepScannerExtensions.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -namespace TestStack.BDDfy.Tests.Scanner.ReflectiveScanner -{ - internal static class StepScannerExtensions - { - internal static IEnumerable Scan(this IStepScanner scanner, ITestContext testContext) - { - // ToDo: this is rather hacky and is not DRY. Should think of a way to get rid of this - return new ReflectiveScenarioScanner() - .GetMethodsOfInterest(testContext.TestObject.GetType()) - .SelectMany(x => scanner.Scan(testContext, x)) - .OrderBy(s => s.ExecutionOrder) - .ToList(); - } - } -} diff --git a/src/TestStack.BDDfy.Tests/Scanner/ReflectiveScanner/WhenCombinationOfExecutableAttributeAndMethodNamingConventionIsUsed.cs b/src/TestStack.BDDfy.Tests/Scanner/ReflectiveScanner/WhenCombinationOfExecutableAttributeAndMethodNamingConventionIsUsed.cs deleted file mode 100644 index 2d80844e..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/ReflectiveScanner/WhenCombinationOfExecutableAttributeAndMethodNamingConventionIsUsed.cs +++ /dev/null @@ -1,140 +0,0 @@ -using System; -using System.Linq; -using System.Linq.Expressions; -using Shouldly; -using TestStack.BDDfy.Configuration; -using Xunit; - -namespace TestStack.BDDfy.Tests.Scanner.ReflectiveScanner -{ - public class WhenCombinationOfExecutableAttributeAndMethodNamingConventionIsUsed - { - private Scenario _scenario; - private ScenarioWithMixedSteps _sut; - - private class ScenarioWithMixedSteps - { - public void When() - { - } - - [AndWhen] - public void LegacyTransitionMethod() - { - - } - - [AndGiven] - public void ThenThisMethodIsFoundAsAGivenStepNotThenStep() - {} - - public void Then() - { - } - - public void Given() - { - } - - [AndThen] - public void AndThen() - { - } - - [Then] - public void TestThatSomethingIsRight() - { - } - - [AndThen] - public void TestThatSomethingIsWrong() - { - } - - [IgnoreStep] - public void ThenIAmNotAStep() - { - } - } - - public WhenCombinationOfExecutableAttributeAndMethodNamingConventionIsUsed() - { - _sut = new ScenarioWithMixedSteps(); - _scenario = - new ReflectiveScenarioScanner( - new IStepScanner[] - { - new ExecutableAttributeStepScanner(), - new DefaultMethodNameStepScanner() - }).Scan(TestContext.GetContext(_sut)).First(); - } - - [Fact] - public void ScenarioTextIsSetUsingClassName() - { - _scenario.Title.ShouldBe("Scenario with mixed steps"); - } - - [Fact] - public void GivenStepIsScanned() - { - VerifyStepAndItsProperties(() => _sut.Given(), ExecutionOrder.SetupState); - } - - [Fact] - public void ExecutableAttributesHaveHigherPriorityThanNamingConventions() - { - VerifyStepAndItsProperties(() => _sut.ThenThisMethodIsFoundAsAGivenStepNotThenStep(), ExecutionOrder.ConsecutiveSetupState); - } - - [Fact] - public void WhenStepIsScanned() - { - VerifyStepAndItsProperties(() => _sut.When(), ExecutionOrder.Transition); - } - - [Fact] - public void LegacyTransitionStepIsScanned() - { - VerifyStepAndItsProperties(() => _sut.LegacyTransitionMethod(), ExecutionOrder.ConsecutiveTransition); - } - - [Fact] - public void ThenStepIsScanned() - { - VerifyStepAndItsProperties(() => _sut.Then(), ExecutionOrder.Assertion); - } - - [Fact] - public void AndThenStepIsScanned() - { - VerifyStepAndItsProperties(() => _sut.AndThen(), ExecutionOrder.ConsecutiveAssertion); - } - - [Fact] - public void LegacyAssertionStepIsScanned() - { - VerifyStepAndItsProperties(() => _sut.TestThatSomethingIsRight(), ExecutionOrder.Assertion); - } - - [Fact] - public void LegacyConsecutiveAssertionStepIsScanned() - { - VerifyStepAndItsProperties(() => _sut.TestThatSomethingIsWrong(), ExecutionOrder.ConsecutiveAssertion); - } - - void VerifyStepAndItsProperties(Expression stepMethodAction, ExecutionOrder expectedOrder, int expectedCount = 1) - { - var matchingSteps = _scenario.Steps.Where(s => s.Title.Trim() == Configurator.Humanizer.Humanize(Helpers.GetMethodInfo(stepMethodAction).Name)); - matchingSteps.Count().ShouldBe(expectedCount); - matchingSteps.All(s => s.ExecutionOrder == expectedOrder).ShouldBe(true); - } - - [Fact] - public void IgnoredMethodShouldNotBeAddedToSteps() - { - var matchingSteps = _scenario.Steps.Where(s => s.Title == Configurator.Humanizer.Humanize(Helpers.GetMethodInfo(() => _sut.ThenIAmNotAStep()).Name)); - matchingSteps.ShouldBeEmpty(); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Scanner/ReflectiveScanner/WhenMethodNamesFollowNamingConventionsOtherThanGivenWhenThen.cs b/src/TestStack.BDDfy.Tests/Scanner/ReflectiveScanner/WhenMethodNamesFollowNamingConventionsOtherThanGivenWhenThen.cs deleted file mode 100644 index 9693ecad..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/ReflectiveScanner/WhenMethodNamesFollowNamingConventionsOtherThanGivenWhenThen.cs +++ /dev/null @@ -1,100 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using Shouldly; -using TestStack.BDDfy.Configuration; -using Xunit; - -namespace TestStack.BDDfy.Tests.Scanner.ReflectiveScanner -{ - public class WhenMethodNamesFollowNamingConventionsOtherThanGivenWhenThen - { - private List _steps; - ScenarioClass _scenario; - - public WhenMethodNamesFollowNamingConventionsOtherThanGivenWhenThen() - { - var specEndMatcher = new MethodNameMatcher(s => s.EndsWith("specification", StringComparison.OrdinalIgnoreCase), false, ExecutionOrder.SetupState, true); - var specStartMatcher = new MethodNameMatcher(s => s.StartsWith("specification", StringComparison.OrdinalIgnoreCase), false, ExecutionOrder.SetupState, true); - var setupMethod = new MethodNameMatcher(s => s.Equals("Setup", StringComparison.OrdinalIgnoreCase), false, ExecutionOrder.SetupState, false); - var assertMatcher = new MethodNameMatcher(s => s.StartsWith("Assert", StringComparison.Ordinal), true, ExecutionOrder.Assertion, true); - var andAssertMatcher = new MethodNameMatcher(s => s.StartsWith("AndAssert", StringComparison.Ordinal), true, ExecutionOrder.ConsecutiveAssertion, true); - var methodNameMatchers = new[] { assertMatcher, andAssertMatcher, specEndMatcher, specStartMatcher, setupMethod }; - _scenario = new ScenarioClass(); - var scanner = new MethodNameStepScanner(s => s, methodNameMatchers); - _steps = scanner.Scan(TestContext.GetContext(_scenario)).ToList(); - } - - class ScenarioClass - { - public void Setup() - { - } - - public void AndAssertThat() - { - } - - public void AssertThis() - { - } - - public void ThisMethodSpecificationShouldNotBeIncluded() - { - } - - public void SpecificationAppearingInTheBeginningOfTheMethodName() - { - } - - public void AppearingAtTheEndOfTheMethodNameSpecification() - { - } - - [IgnoreStep] - public void SpecificationToIgnore() - { - } - } - - [Fact] - public void TheStepsAreFoundUsingConventionInjection() - { - _steps.Count.ShouldBe(5); - } - - [Fact] - public void TheSetupMethodIsPickedAsNonAsserting() - { - var setupMethod = _steps.Single(s => s.Title == "Setup"); - setupMethod.ExecutionOrder.ShouldBe(ExecutionOrder.SetupState); - setupMethod.ShouldReport.ShouldBe(false); - setupMethod.Asserts.ShouldBe(false); - } - - [Fact] - public void TheCorrectSpecificationStepsAreFound() - { - AssertSpecificationStepIsScannedProperly(() => _scenario.SpecificationAppearingInTheBeginningOfTheMethodName()); - AssertSpecificationStepIsScannedProperly(() => _scenario.AppearingAtTheEndOfTheMethodNameSpecification()); - } - - [Fact] - public void IncorrectSpecificationStepIsNotAdded() - { - var specMethod = _steps.Where(s => s.Title == "This method specification should not be included"); - specMethod.ShouldBeEmpty(); - } - - void AssertSpecificationStepIsScannedProperly(Expression getSpecMethod) - { - var specMethods = _steps.Where(s => s.Title.Trim() == Configurator.Humanizer.Humanize(Helpers.GetMethodInfo(getSpecMethod).Name)); - specMethods.Count().ShouldBe(1); - var specStep = specMethods.First(); - specStep.Asserts.ShouldBe(false); - specStep.ShouldReport.ShouldBe(true); - specStep.ExecutionOrder.ShouldBe(ExecutionOrder.SetupState); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Scanner/ReflectiveScanner/WhenStepScannerFactoryAsyncMethods.cs b/src/TestStack.BDDfy.Tests/Scanner/ReflectiveScanner/WhenStepScannerFactoryAsyncMethods.cs deleted file mode 100644 index fdf67b5a..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/ReflectiveScanner/WhenStepScannerFactoryAsyncMethods.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using System.Reflection; -using System.Threading.Tasks; -using Shouldly; -using TestStack.BDDfy.Processors; -using Xunit; - -namespace TestStack.BDDfy.Tests.Scanner.ReflectiveScanner -{ - public class WhenStepScannerFactoryAsyncMethods - { - [Fact] - public void CallingAsyncTaskWhichThrowsIsObservedAndRethrown() - { - var stepAction = StepActionFactory.GetStepAction(o => AsyncTaskMethod(o)); - Should.Throw(()=> AsyncTestRunner.Run(() => stepAction(new SomeScenario()))); - } - - [Fact] - public void CallingAsyncVoidWhichThrowsIsObservedAndRethrown() - { - var stepAction = StepActionFactory.GetStepAction(s=>AsyncVoidMethod(s)); - - Should.Throw(()=> AsyncTestRunner.Run(() => stepAction(new SomeScenario()))); - } - - [Fact] - public void InvokingAsyncTaskWhichThrowsIsObservedAndRethrown() - { - var methodInfo = typeof(WhenStepScannerFactoryAsyncMethods).GetMethod("AsyncVoidMethod", BindingFlags.Instance | BindingFlags.NonPublic); - var stepAction = StepActionFactory.GetStepAction(methodInfo, new object[] { new SomeScenario() }); - - Should.Throw(()=> AsyncTestRunner.Run(() => stepAction(this))); - } - - [Fact] - public void InvokingAsyncVoidWhichThrowsIsObservedAndRethrown() - { - var methodInfo = typeof(WhenStepScannerFactoryAsyncMethods).GetMethod("AsyncTaskMethod", BindingFlags.Instance | BindingFlags.NonPublic); - var stepAction = StepActionFactory.GetStepAction(methodInfo, new object[] { new SomeScenario() }); - - Should.Throw(()=> AsyncTestRunner.Run(() => stepAction(this))); - } - - private async void AsyncVoidMethod(SomeScenario someScenario) - { - await Task.Yield(); - throw new ArgumentException(); - } - - private async Task AsyncTaskMethod(SomeScenario obj) - { - await Task.Yield(); - throw new ArgumentException(); - } - - private class SomeScenario - { - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Scanner/ReflectiveScanner/WhenStepsAreDefinedInABaseClass.cs b/src/TestStack.BDDfy.Tests/Scanner/ReflectiveScanner/WhenStepsAreDefinedInABaseClass.cs deleted file mode 100644 index 8131d8f7..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/ReflectiveScanner/WhenStepsAreDefinedInABaseClass.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System.Linq; -using Shouldly; -using TestStack.BDDfy.Configuration; -using Xunit; - -namespace TestStack.BDDfy.Tests.Scanner.ReflectiveScanner -{ - public class WhenStepsAreDefinedInABaseClass - { - private Story _story; - - class TheBaseClass - { - public void GivenInTheBaseClass(){} - public void WhenInTheBaseClass(){} - public void ThenInTheBaseClass(){} - } - - class TheSubClass : TheBaseClass - { - public void GivenInTheSubClass(){} - public void WhenInTheSubClass(){} - public void ThenInTheSubClass(){} - } - - void Context() - { - _story = new TheSubClass().BDDfy(); - } - - Scenario Scenario - { - get - { - return _story.Scenarios.Single(); - } - } - - [RunStepWithArgs("GivenInTheBaseClass")] - [RunStepWithArgs("WhenInTheBaseClass")] - [RunStepWithArgs("ThenInTheBaseClass")] - void ThenTheFollowingStepFromBaseClassIsScanned(string stepName) - { - Scenario.Steps.Count(s => s.Title == Configurator.Humanizer.Humanize(stepName)).ShouldBe(1); - } - - [RunStepWithArgs("GivenInTheSubClass")] - [RunStepWithArgs("WhenInTheSubClass")] - [RunStepWithArgs("ThenInTheSubClass")] - void ThenTheFollowingStepFromSubClassScanned(string stepName) - { - Scenario.Steps.Count(s => s.Title == Configurator.Humanizer.Humanize(stepName)).ShouldBe(1); - } - - [Fact] - public void Execute() - { - this.BDDfy(); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Scanner/ReflectiveScanner/WhenStepsReturnTheirText.cs b/src/TestStack.BDDfy.Tests/Scanner/ReflectiveScanner/WhenStepsReturnTheirText.cs deleted file mode 100644 index 96901c6c..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/ReflectiveScanner/WhenStepsReturnTheirText.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Tests.Scanner.ReflectiveScanner -{ - public class WhenStepsReturnTheirText - { - class TestClassWithStepsReturningTheirText(int input1, string input2) - { - private readonly int _input1 = input1; - private readonly string _input2 = input2; - - IEnumerable Given() - { - yield return string.Format("Given inputs {0} and {1}", _input1, _input2); - } - - [RunStepWithArgs("input 2", 123)] - IEnumerable When(string input1, int input2) - { - yield return string.Format("When {0} is applied on {1}", input1, input2); - } - - IEnumerable ThenSomeAssertions() - { - yield break; - } - } - - [Fact] - public void Test() - { - var testObject = new TestClassWithStepsReturningTheirText(1, "some input"); - var steps = new DefaultMethodNameStepScanner().Scan(TestContext.GetContext(testObject)).ToList(); - - AssertStep(steps[0], "Given inputs 1 and some input", ExecutionOrder.SetupState); - AssertStep(steps[1], "When input 2 is applied on 123", ExecutionOrder.Transition); - AssertStep(steps[2], "Then some assertions", ExecutionOrder.Assertion, true); - } - - private static void AssertStep(Step step, string stepTitle, ExecutionOrder order, bool asserts = false, bool shouldReport = true) - { - step.Title.Trim().ShouldBe(stepTitle); - step.Asserts.ShouldBe(asserts); - step.ExecutionOrder.ShouldBe(order); - step.ShouldReport.ShouldBe(shouldReport); - } - - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Scanner/ReflectiveScanner/WhenTestClassFollowsGivenWhenThenNamingConvention.cs b/src/TestStack.BDDfy.Tests/Scanner/ReflectiveScanner/WhenTestClassFollowsGivenWhenThenNamingConvention.cs deleted file mode 100644 index b3ace10e..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/ReflectiveScanner/WhenTestClassFollowsGivenWhenThenNamingConvention.cs +++ /dev/null @@ -1,83 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Tests.Scanner.ReflectiveScanner -{ - public class WhenTestClassFollowsGivenWhenThenNamingConvention - { - private List _steps; - private TypeWithoutAttribute _typeWithoutAttribute; - - private class TypeWithoutAttribute - { - public void EstablishContext() {} - public void Setup(){} - public void AndThenAnotherThingIsTrue() {} - public void AndWhenSomethingElseHappens() {} - public void And_When_another_THING_Happens() {} - public void ButWhenSomethingDoesNotHappen() { } - public void But_When_another_THING_does_not_happen() { } - public void GivenSomeState() {} - public void AndSomethingElseToo() { } - public void WhenSomethingHappens() {} - public void AndGivenAnotherState() { } - public void And_Given_Some_OTHER_state() { } - public void AndGiven_some_other_initial_state() { } - public void ButGiven_some_initial_state_is_not_set() { } - public void ThenSomethingIsTrue(){} - public void TearDown(){} - public void And_YET_another_thing(){} - public void AndThen_something_else() {} - public void And_then_there_was_that_one_time() {} - public void But_some_condition_is_not_true() {} - public void ButSomeOtherConditionIsNotTrue() {} - public void ButThenSomeOtherConditionIsNotTrueEither() {} - public void But_then_again_some_condition_is_not_true() { } - public void But_Given_Some_OTHER_state_is_not_set() { } - } - - [Fact] - public void VerifyScannedSteps() - { - _typeWithoutAttribute = new TypeWithoutAttribute(); - _steps = new DefaultMethodNameStepScanner().Scan(TestContext.GetContext(_typeWithoutAttribute)).ToList(); - int stepIndex = 0; - - _steps.Count.ShouldBe(24); - AssertStep(_steps[stepIndex++], "Establish context", ExecutionOrder.Initialize, false, false); - AssertStep(_steps[stepIndex++], "Setup", ExecutionOrder.Initialize, false, false); - AssertStep(_steps[stepIndex++], "Given some state", ExecutionOrder.SetupState); - AssertStep(_steps[stepIndex++], "And another state", ExecutionOrder.ConsecutiveSetupState); - AssertStep(_steps[stepIndex++], "And Some OTHER state", ExecutionOrder.ConsecutiveSetupState); - AssertStep(_steps[stepIndex++], "And some other initial state", ExecutionOrder.ConsecutiveSetupState); - AssertStep(_steps[stepIndex++], "But some initial state is not set", ExecutionOrder.ConsecutiveSetupState); - AssertStep(_steps[stepIndex++], "But Some OTHER state is not set", ExecutionOrder.ConsecutiveSetupState); - AssertStep(_steps[stepIndex++], "When something happens", ExecutionOrder.Transition); - AssertStep(_steps[stepIndex++], "And something else happens", ExecutionOrder.ConsecutiveTransition); - AssertStep(_steps[stepIndex++], "And another THING Happens", ExecutionOrder.ConsecutiveTransition); - AssertStep(_steps[stepIndex++], "But something does not happen", ExecutionOrder.ConsecutiveTransition); - AssertStep(_steps[stepIndex++], "But another THING does not happen", ExecutionOrder.ConsecutiveTransition); - AssertStep(_steps[stepIndex++], "Then something is true", ExecutionOrder.Assertion, true); - AssertStep(_steps[stepIndex++], "And another thing is true", ExecutionOrder.ConsecutiveAssertion, true); - AssertStep(_steps[stepIndex++], "And something else too", ExecutionOrder.ConsecutiveAssertion, true); - AssertStep(_steps[stepIndex++], "And YET another thing", ExecutionOrder.ConsecutiveAssertion, true); - AssertStep(_steps[stepIndex++], "And something else", ExecutionOrder.ConsecutiveAssertion, true); - AssertStep(_steps[stepIndex++], "And there was that one time", ExecutionOrder.ConsecutiveAssertion, true); - AssertStep(_steps[stepIndex++], "But some condition is not true", ExecutionOrder.ConsecutiveAssertion, true); - AssertStep(_steps[stepIndex++], "But some other condition is not true", ExecutionOrder.ConsecutiveAssertion, true); - AssertStep(_steps[stepIndex++], "But some other condition is not true either", ExecutionOrder.ConsecutiveAssertion, true); - AssertStep(_steps[stepIndex++], "But again some condition is not true", ExecutionOrder.ConsecutiveAssertion, true); - AssertStep(_steps[stepIndex++], "Tear down", ExecutionOrder.TearDown, asserts:false, shouldReport:false); - } - - private static void AssertStep(Step step, string stepTitle, ExecutionOrder order, bool asserts = false, bool shouldReport = true) - { - step.Title.Trim().ShouldBe(stepTitle); - step.Asserts.ShouldBe(asserts); - step.ExecutionOrder.ShouldBe(order); - step.ShouldReport.ShouldBe(shouldReport); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Scanner/ReflectiveScanner/WhenTestClassUsesExecutableAttributes.cs b/src/TestStack.BDDfy.Tests/Scanner/ReflectiveScanner/WhenTestClassUsesExecutableAttributes.cs deleted file mode 100644 index 12a8c0fc..00000000 --- a/src/TestStack.BDDfy.Tests/Scanner/ReflectiveScanner/WhenTestClassUsesExecutableAttributes.cs +++ /dev/null @@ -1,176 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using Shouldly; -using TestStack.BDDfy.Configuration; -using Xunit; - -namespace TestStack.BDDfy.Tests.Scanner.ReflectiveScanner -{ - public class WhenTestClassUsesExecutableAttributes - { - private TypeWithAttribute _typeWithAttribute; - private List _steps; - - private class TypeWithAttribute - { - public const string MethodTextForWhenSomethingHappens = "When Something Happens"; - public const string MethodTextForAndThen = "The text for the AndThen part"; - - [Then] - [RunStepWithArgs(1, 2)] - [RunStepWithArgs(3, 4)] - public void Then(int input1, int input2) { } - - public void ThenIShouldNotBeReturnedBecauseIDoNotHaveAttributes() { } - - [When(StepTitle = MethodTextForWhenSomethingHappens)] - public void WhenStep() { } - - public void ButWhenSomethingDoesNotHappen() { } - - [ButWhen] - public void AndSomethingHasNotHappened() { } - public void WhenStep_NoAttributeIsProvided() { } - - [Given] - public void Given() { } - - public void GivenWithoutAttribute() { } - - [ButGiven] - public void SetupShouldAvoidSomethings() { } - - public void ButGivenSomethingIsNotSetup() {} - - [AndWhen] - public void TheOtherPartOfWhen() { } - - [AndThen(StepTitle = MethodTextForAndThen)] - public void AndThen() { } - - [AndGiven] - public void SomeOtherPartOfTheGiven() { } - - [But] - public void IDontWantThisToBeTrue() { } - - [Executable(ExecutionOrder.Assertion, "", ShouldReport = false)] - public void Executable() { } - } - - public WhenTestClassUsesExecutableAttributes() - { - _typeWithAttribute = new TypeWithAttribute(); - _steps = new ExecutableAttributeStepScanner().Scan(TestContext.GetContext(_typeWithAttribute)).ToList(); - } - - private static string GetStepTextFromMethodName(Expression methodInfoAction) - { - return Configurator.Humanizer.Humanize(Helpers.GetMethodInfo(methodInfoAction).Name); - } - - [Fact] - public void DecoratedMethodsAreReturned() - { - _steps.Count.ShouldBe(11); - } - - [Fact] - public void Given() - { - var givenStep = _steps.Single(s => s.Title == "Given"); - givenStep.ExecutionOrder.ShouldBe(ExecutionOrder.SetupState); - givenStep.Asserts.ShouldBe(false); - givenStep.Title.Trim().ShouldBe(GetStepTextFromMethodName(() => _typeWithAttribute.Given())); - } - - [Fact] - public void AndGiven() - { - var step = _steps.Single(s => s.Title.Trim() == "Some other part of the given"); - step.ExecutionOrder.ShouldBe(ExecutionOrder.ConsecutiveSetupState); - step.Asserts.ShouldBe(false); - step.Title.Trim().ShouldBe(GetStepTextFromMethodName(() => _typeWithAttribute.SomeOtherPartOfTheGiven())); - } - - [Fact] - public void ButGiven() - { - var step = _steps.Single(s => s.Title.Trim() == "Setup should avoid somethings"); - step.ExecutionOrder.ShouldBe(ExecutionOrder.ConsecutiveSetupState); - step.Asserts.ShouldBe(false); - step.Title.Trim().ShouldBe(GetStepTextFromMethodName(() => _typeWithAttribute.SetupShouldAvoidSomethings())); - } - - [Fact] - public void When() - { - var step = _steps.Single(s => s.Title == TypeWithAttribute.MethodTextForWhenSomethingHappens); - step.ExecutionOrder.ShouldBe(ExecutionOrder.Transition); - step.Title.ShouldBe(TypeWithAttribute.MethodTextForWhenSomethingHappens); - step.Asserts.ShouldBe(false); - } - - [Fact] - public void TheOtherPartOfWhen() - { - var step = _steps.Single(s => s.Title.Trim() == "The other part of when"); - step.ExecutionOrder.ShouldBe(ExecutionOrder.ConsecutiveTransition); - step.Title.Trim().ShouldBe(GetStepTextFromMethodName(() => _typeWithAttribute.TheOtherPartOfWhen())); - step.Asserts.ShouldBe(false); - } - - [Fact] - public void ButWhen() - { - var step = _steps.Single(s => s.Title.Trim() == "And something has not happened"); - step.ExecutionOrder.ShouldBe(ExecutionOrder.ConsecutiveTransition); - step.Title.Trim().ShouldBe(GetStepTextFromMethodName(() => _typeWithAttribute.AndSomethingHasNotHappened())); - step.Asserts.ShouldBe(false); - } - - [Fact] - public void ThenStepsWithArgs() - { - var steps = _steps.Where(s => s.Title == "Then 1, 2" || s.Title == "Then 3, 4").ToList(); - steps.All(s => s.ExecutionOrder == ExecutionOrder.Assertion).ShouldBe(true); - steps.All(s => s.Asserts).ShouldBe(true); - steps.All(s => s.Title.EndsWith(" 1, 2") || s.Title.EndsWith(" 3, 4")).ShouldBe(true); - } - - [Fact] - public void AndThen() - { - var step = _steps.Single(s => s.Title.Trim() == TypeWithAttribute.MethodTextForAndThen); - step.ExecutionOrder.ShouldBe(ExecutionOrder.ConsecutiveAssertion); - step.Asserts.ShouldBe(true); - step.Title.Trim().ShouldBe(TypeWithAttribute.MethodTextForAndThen); - } - - [Fact] - public void But() - { - var step = _steps.Single(s => s.Title == "I dont want this to be true"); - step.ExecutionOrder.ShouldBe(ExecutionOrder.ConsecutiveAssertion); - step.Asserts.ShouldBe(true); - } - - [Fact] - public void ExecutableAttributesDefaultToShouldReport() - { - foreach (var step in _steps.Where(s => s.Title != "Executable")) - { - step.ShouldReport.ShouldBe(true); - } - } - - [Fact] - public void CanPreventExecutableAttributesReporting() - { - var step = _steps.First(s => s.Title == "Executable"); - step.ShouldReport.ShouldBe(false); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Stories/CanUseACustomStoryAttribute.cs b/src/TestStack.BDDfy.Tests/Stories/CanUseACustomStoryAttribute.cs deleted file mode 100644 index 5df7282a..00000000 --- a/src/TestStack.BDDfy.Tests/Stories/CanUseACustomStoryAttribute.cs +++ /dev/null @@ -1,50 +0,0 @@ -using NUnit.Framework; -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Tests.Stories -{ - class InOrderToStoryAttribute : StoryNarrativeAttribute - { - // ReSharper disable InconsistentNaming - private const string As_a_prefix = "As a"; - private const string In_order_to_prefix = "In order to"; - private const string I_want_prefix = "I want"; - // ReSharper restore InconsistentNaming - - public string InOrderTo - { - get { return Narrative1; } - set { Narrative1 = CleanseProperty(value, In_order_to_prefix); } - } - - public string AsA - { - get { return Narrative2; } - set { Narrative2 = CleanseProperty(value, As_a_prefix); } - } - - public string IWant - { - get { return Narrative3; } - set { Narrative3 = CleanseProperty(value, I_want_prefix); } - } - } - - [InOrderToStory( - InOrderTo = "do something", - AsA = "programmer", - IWant = "this to work")] - public class CanUseACustomStoryAttribute - { - [Fact] - public void When_InOrderTo_is_specified_the_InOrderTo_syntax_is_used() - { - var story = new DummyScenario().BDDfy(); - - story.Metadata.Narrative1.ShouldBe("In order to do something"); - story.Metadata.Narrative2.ShouldBe("As a programmer"); - story.Metadata.Narrative3.ShouldBe("I want this to work"); - } - } -} diff --git a/src/TestStack.BDDfy.Tests/Stories/DummyScenario.cs b/src/TestStack.BDDfy.Tests/Stories/DummyScenario.cs deleted file mode 100644 index 1b1727f4..00000000 --- a/src/TestStack.BDDfy.Tests/Stories/DummyScenario.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace TestStack.BDDfy.Tests.Stories -{ - public class DummyScenario - { - void WhenScenarioIsDecoratedWithStory() - { - } - - void ThenScenarioIsExecutedAsPartOfStory() - { - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Stories/SharedStoryNotion.cs b/src/TestStack.BDDfy.Tests/Stories/SharedStoryNotion.cs deleted file mode 100644 index 5dd1c262..00000000 --- a/src/TestStack.BDDfy.Tests/Stories/SharedStoryNotion.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace TestStack.BDDfy.Tests.Stories -{ - [Story( - AsA = "As a programmer", - IWant = "I want to be able to explicitly specify a story", - SoThat = "So that I can share a story definition between several scenarios")] - public class SharedStoryNotion - { - - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Stories/StoryCanBeSpecifiedInFluentMode.cs b/src/TestStack.BDDfy.Tests/Stories/StoryCanBeSpecifiedInFluentMode.cs deleted file mode 100644 index 398a5274..00000000 --- a/src/TestStack.BDDfy.Tests/Stories/StoryCanBeSpecifiedInFluentMode.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Tests.Stories -{ - [Story] - public class StoryCanBeSpecifiedInFluentMode - { - [Fact] - public void Verify() - { - var story = this - .When(_ => WhenStoryIsSpecifiedInFluentMode()) - .Then(_ => ThenTheSpecifiedStoryShouldBeUsed()) - .BDDfy(); - - story.Metadata.Type.ShouldBe(typeof(SharedStoryNotion)); - } - - void WhenStoryIsSpecifiedInFluentMode() - { - - } - - void ThenTheSpecifiedStoryShouldBeUsed() - { - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Stories/StoryCanBeSpecifiedInReflectiveMode.cs b/src/TestStack.BDDfy.Tests/Stories/StoryCanBeSpecifiedInReflectiveMode.cs deleted file mode 100644 index c8d394c4..00000000 --- a/src/TestStack.BDDfy.Tests/Stories/StoryCanBeSpecifiedInReflectiveMode.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Tests.Stories -{ - [Story] - public class StoryCanBeSpecifiedInReflectiveMode - { - [Fact] - public void Verify() - { - var story = this.BDDfy(); - - story.Metadata.Type.ShouldBe(typeof(SharedStoryNotion)); - } - - void WhenStoryIsSpecifiedInReflectiveMode() - { - - } - - void ThenTheSpecifiedStoryShouldBeUsed() - { - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Stories/StoryClassAndScenarioClassAreTheSame.cs b/src/TestStack.BDDfy.Tests/Stories/StoryClassAndScenarioClassAreTheSame.cs deleted file mode 100644 index e105b2c2..00000000 --- a/src/TestStack.BDDfy.Tests/Stories/StoryClassAndScenarioClassAreTheSame.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System.Linq; -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Tests.Stories -{ - public class StoryClassAndScenarioClassAreTheSame - { - private Story _story; - - [Story( - AsA = "As a story with no scenarios specified using attributes", - IWant = "I want to be considered as a scenario", - SoThat = "So that single scenario stories do not have to separate into two classes")] - public class StoryAsScenario - { - [Then(StepTitle = "See?! I am a normal scenario even though I have been decorated with StoryAttribute")] - void SeeIAmAScenario() - { - } - } - - void WhenTheStoryIsBddified() - { - _story = new StoryAsScenario().BDDfy(); - } - - void ThenStoryIsReturnedAsAStory() - { - _story.Metadata.Type.ShouldBe(typeof(StoryAsScenario)); - } - - [AndThen(StepTitle = "and as a scenario")] - void andAsAScenario() - { - _story.Scenarios.Count().ShouldBe(1); - var scenario = _story.Scenarios.First(); - scenario.TestObject.ShouldBeAssignableTo(); - } - - void andTheNarrativeIsReturnedAsExpected() - { - var expectedNarrative = (StoryAttribute)typeof(StoryAsScenario).GetCustomAttributes(typeof(StoryAttribute), false).First(); - _story.Metadata.ShouldNotBe(null); - _story.Metadata.Narrative1.ShouldBe(expectedNarrative.AsA); - _story.Metadata.Narrative2.ShouldBe(expectedNarrative.IWant); - _story.Metadata.Narrative3.ShouldBe(expectedNarrative.SoThat); - } - - [Fact] - public void Execute() - { - try - { - // we need TestObject for this test; so I disable StoryCache processor for this one test - BDDfy.Configuration.Configurator.Processors.StoryCache.Disable(); - - this.BDDfy(); - } - finally - { - BDDfy.Configuration.Configurator.Processors.StoryCache.Enable(); - } - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Stories/StoryClassBase.cs b/src/TestStack.BDDfy.Tests/Stories/StoryClassBase.cs deleted file mode 100644 index 4c7f07f1..00000000 --- a/src/TestStack.BDDfy.Tests/Stories/StoryClassBase.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace TestStack.BDDfy.Tests.Stories -{ - [Story( - Title = StoryTitle, - TitlePrefix = StoryTitlePrefix, - AsA = "As a programmer", - IWant = "I want BDDfy to inherit StoryAttribute", - SoThat = "So that I can put some shared logic on a base story class")] - public abstract class StoryClassBase - { - protected const string StoryTitle = "Story base class"; - protected const string StoryTitlePrefix = "Specifications: "; - - protected void GivenTheStoryAttributeIsSetOnTheBaseClass() - { - - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Stories/StoryDouble.cs b/src/TestStack.BDDfy.Tests/Stories/StoryDouble.cs deleted file mode 100644 index 74e77bdd..00000000 --- a/src/TestStack.BDDfy.Tests/Stories/StoryDouble.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Linq; -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Tests.Stories -{ - [Story( - AsA = "As a good programmer", - IWant = "I want to be able to write my stories as part of my BDD tests", - SoThat = "So I can get business readable requirements")] - public class StoryDouble - { - [Fact] - public void ScanningAScenarioWithoutArgsFromAStoryClass() - { - var testObject = new DummyScenario(); - var scanner = new DefaultScanner(TestContext.GetContext(testObject), new ReflectiveScenarioScanner(new DefaultMethodNameStepScanner()), typeof(StoryDouble)); - var story = scanner.Scan(); - - story.Metadata.Type.ShouldBe(typeof(StoryDouble)); - story.Scenarios.Count().ShouldBe(1); - story.Scenarios.Single().TestObject.ShouldBeAssignableTo(); - - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Stories/StorySubclass.cs b/src/TestStack.BDDfy.Tests/Stories/StorySubclass.cs deleted file mode 100644 index 0e28e36b..00000000 --- a/src/TestStack.BDDfy.Tests/Stories/StorySubclass.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Tests.Stories -{ - public class StoryAttributeIsInheritedFromBaseClass : StoryClassBase - { - Story _story; - - [Fact] - public void Verify() - { - _story = this.BDDfy(); - _story.Metadata.ShouldNotBe(null); - _story.Metadata.Title.ShouldBe(StoryTitle); - _story.Metadata.TitlePrefix.ShouldBe(StoryTitlePrefix); - } - - void WhenTheSubclassIsBddified() - { - } - - void ThenTheStoryAttributeIsFoundAndAssociatedWithTheSubStoryClass() - { - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Stories/WhenAStoryHasUriAndImageMetadata.cs b/src/TestStack.BDDfy.Tests/Stories/WhenAStoryHasUriAndImageMetadata.cs deleted file mode 100644 index d585ab83..00000000 --- a/src/TestStack.BDDfy.Tests/Stories/WhenAStoryHasUriAndImageMetadata.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Xunit; -using Shouldly; - -namespace TestStack.BDDfy.Tests.Stories -{ - [Story( - AsA = "programmer", - IWant = "to attach an uri and image metadata to a story", - SoThat = "my output report communicates better to my stakeholders", - StoryUri = "http://teststoryuri.com.au", - ImageUri = "http://teststoryuri.com.au/storyimg.png")] - public class WhenAStoryHasUriAndImageMetadata - { - [Fact] - public void Then_it_is_injected_by_BDDfy() - { - var story = new DummyScenario().BDDfy(); - story.Metadata.StoryUri.ShouldBe("http://teststoryuri.com.au"); - story.Metadata.ImageUri.ShouldBe("http://teststoryuri.com.au/storyimg.png"); - } - } -} diff --git a/src/TestStack.BDDfy.Tests/Stories/WhenStoryAttibuteMissesAsATextInAsAProperty.cs b/src/TestStack.BDDfy.Tests/Stories/WhenStoryAttibuteMissesAsATextInAsAProperty.cs deleted file mode 100644 index 9347923a..00000000 --- a/src/TestStack.BDDfy.Tests/Stories/WhenStoryAttibuteMissesAsATextInAsAProperty.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Tests.Stories -{ - [Story( - AsA = "programmer", - IWant = "I want the missing 'As a' to be added to story metadata", - SoThat = "So that I don't have to duplicate it on the string")] - public class WhenStoryAttibuteMissesAsATextInAsAProperty - { - [Fact] - public void Then_it_is_injected_by_BDDfy() - { - var story = new DummyScenario().BDDfy(); - - story.Metadata.Narrative1.ShouldBe("As a programmer"); - story.Metadata.Narrative2.ShouldBe("I want the missing 'As a' to be added to story metadata"); - story.Metadata.Narrative3.ShouldBe("So that I don't have to duplicate it on the string"); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Stories/WhenStoryAttibuteMissesDuplicateTextsInProperties.cs b/src/TestStack.BDDfy.Tests/Stories/WhenStoryAttibuteMissesDuplicateTextsInProperties.cs deleted file mode 100644 index f5c1b21a..00000000 --- a/src/TestStack.BDDfy.Tests/Stories/WhenStoryAttibuteMissesDuplicateTextsInProperties.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Tests.Stories -{ - [Story( - AsA = "programmer", - IWant = "the missing texts to be added to story metadata", - SoThat = "I don't have to duplicate it on the string")] - public class WhenStoryAttibuteMissesDuplicateTextsInProperties - { - [Fact] - public void Then_it_is_injected_by_BDDfy() - { - var story = new DummyScenario().BDDfy(); - - story.Metadata.Narrative1.ShouldBe("As a programmer"); - story.Metadata.Narrative2.ShouldBe("I want the missing texts to be added to story metadata"); - story.Metadata.Narrative3.ShouldBe("So that I don't have to duplicate it on the string"); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Stories/WhenStoryAttibuteMissesIWantTextInIWantProperty.cs b/src/TestStack.BDDfy.Tests/Stories/WhenStoryAttibuteMissesIWantTextInIWantProperty.cs deleted file mode 100644 index a839f597..00000000 --- a/src/TestStack.BDDfy.Tests/Stories/WhenStoryAttibuteMissesIWantTextInIWantProperty.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Tests.Stories -{ - [Story( - AsA = "As a programmer", - IWant = "the missing 'I want' to be added to story metadata", - SoThat = "So that I don't have to duplicate it on the string")] - public class WhenStoryAttibuteMissesIWantTextInIWantProperty - { - [Fact] - public void Then_it_is_injected_by_BDDfy() - { - var story = new DummyScenario().BDDfy(); - - story.Metadata.Narrative1.ShouldBe("As a programmer"); - story.Metadata.Narrative2.ShouldBe("I want the missing 'I want' to be added to story metadata"); - story.Metadata.Narrative3.ShouldBe("So that I don't have to duplicate it on the string"); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/Stories/WhenStoryAttibuteMissesSoThatTextInSoThatProperty.cs b/src/TestStack.BDDfy.Tests/Stories/WhenStoryAttibuteMissesSoThatTextInSoThatProperty.cs deleted file mode 100644 index 32aa0d3b..00000000 --- a/src/TestStack.BDDfy.Tests/Stories/WhenStoryAttibuteMissesSoThatTextInSoThatProperty.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Shouldly; -using Xunit; - -namespace TestStack.BDDfy.Tests.Stories -{ - [Story( - AsA = "As a programmer", - IWant = "I want the missing 'So that' to be added to story metadata", - SoThat = "I don't have to duplicate it on the string")] - public class WhenStoryAttibuteMissesSoThatTextInSoThatProperty - { - [Fact] - public void Then_it_is_injected_by_BDDfy() - { - var story = new DummyScenario().BDDfy(); - - story.Metadata.Narrative1.ShouldBe("As a programmer"); - story.Metadata.Narrative2.ShouldBe("I want the missing 'So that' to be added to story metadata"); - story.Metadata.Narrative3.ShouldBe("So that I don't have to duplicate it on the string"); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/TagsTests.TagsAreReportedInHtmlReport.approved.txt b/src/TestStack.BDDfy.Tests/TagsTests.TagsAreReportedInHtmlReport.approved.txt deleted file mode 100644 index 40a956de..00000000 --- a/src/TestStack.BDDfy.Tests/TagsTests.TagsAreReportedInHtmlReport.approved.txt +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - - BDDfy Test Result 25/03/2014 - - -
-
-
BDDfy
-
A simple BDD framework for .Net developers
-
-
-

Summary:

-
    -
  • -
    -
    Stories
    - 0 -
    -
  • -
  • -
    -
    Scenarios
    - 1 -
    -
  • -
  • -
    -
    Passed
    - 1 -
    -
  • -
  • -
    -
    Inconclusive
    - 0 -
    -
  • -
  • -
    -
    Not Implemented
    - 0 -
    -
  • -
  • -
    -
    Failed
    - 0 -
    -
  • -
-
-
-
-

Details:

- -
-
    -
  • -
    - -
    -
    -
    Tags are reported in html report
    Tag1
    Tag 2
    -
      -
    • - Given a step -
    • -
    -
    -
    -
    -
  • -
-

Tested at: 25/03/2014 11:30:05

-
-
- - - - - - diff --git a/src/TestStack.BDDfy.Tests/TagsTests.TagsAreReportedInMarkdownReport.approved.txt b/src/TestStack.BDDfy.Tests/TagsTests.TagsAreReportedInMarkdownReport.approved.txt deleted file mode 100644 index 73c3d373..00000000 --- a/src/TestStack.BDDfy.Tests/TagsTests.TagsAreReportedInMarkdownReport.approved.txt +++ /dev/null @@ -1,5 +0,0 @@ - -### Tags are reported in markdown report - Given a step - -Tags: `Tag1`, `Tag 2` diff --git a/src/TestStack.BDDfy.Tests/TagsTests.TagsAreReportedInMetroHtmlReport.approved.txt b/src/TestStack.BDDfy.Tests/TagsTests.TagsAreReportedInMetroHtmlReport.approved.txt deleted file mode 100644 index 432816b3..00000000 --- a/src/TestStack.BDDfy.Tests/TagsTests.TagsAreReportedInMetroHtmlReport.approved.txt +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - - - BDDfy Test Result 25/03/2014 - - -
-
-

BDDfy

-

A simple BDD framework for .Net developers

-
-
- -
-
-
-

results

- show steps - hide steps -
-
    -
  • -
    - -
    -
    -
    Tags are reported in metro html report
    Tag1
    Tag 2
    -
      -
    • - Given a step -
    • -
    -
    -
    -
    -
  • -
-
-
-
-

Tested at: 25/03/2014 11:30:05

-

Powered by BDDfy

-
- - - - - diff --git a/src/TestStack.BDDfy.Tests/TagsTests.TagsAreReportedInTextReport.approved.txt b/src/TestStack.BDDfy.Tests/TagsTests.TagsAreReportedInTextReport.approved.txt deleted file mode 100644 index 790f2427..00000000 --- a/src/TestStack.BDDfy.Tests/TagsTests.TagsAreReportedInTextReport.approved.txt +++ /dev/null @@ -1,6 +0,0 @@ - -Scenario: Tags are reported in text report - Given a step - -Tags: Tag1, Tag 2 - diff --git a/src/TestStack.BDDfy.Tests/TagsTests.cs b/src/TestStack.BDDfy.Tests/TagsTests.cs deleted file mode 100644 index 26128025..00000000 --- a/src/TestStack.BDDfy.Tests/TagsTests.cs +++ /dev/null @@ -1,80 +0,0 @@ -#if Approvals -using System; -using Shouldly; -using System.Runtime.CompilerServices; -using TestStack.BDDfy.Reporters; -using TestStack.BDDfy.Reporters.Html; -using TestStack.BDDfy.Reporters.MarkDown; -using TestStack.BDDfy.Tests.Reporters; -using Xunit; - -namespace TestStack.BDDfy.Tests -{ - public class TagsTests - { - [Fact] - [MethodImpl(MethodImplOptions.NoInlining)] - public void TagsAreReportedInTextReport() - { - var story = this.Given(_ => GivenAStep()) - .WithTags("Tag1", "Tag 2") - .BDDfy(); - - var textReporter = new TextReporter(); - textReporter.Process(story); - - textReporter.ToString().ShouldMatchApproved(); - } - - [Fact] - [MethodImpl(MethodImplOptions.NoInlining)] - public void TagsAreReportedInHtmlReport() - { - var model = new HtmlReportModel(this.CreateReportModel()) { - RunDate = new DateTime(2014, 3, 25, 11, 30, 5) - }; - - var sut = new ClassicReportBuilder(); - ReportApprover.Approve(model, sut); - } - - [Fact] - [MethodImpl(MethodImplOptions.NoInlining)] - public void TagsAreReportedInMetroHtmlReport() - { - var reportModel = this.CreateReportModel(); - var model = new HtmlReportModel(reportModel) - { - RunDate = new DateTime(2014, 3, 25, 11, 30, 5) - }; - - var sut = new MetroReportBuilder(); - ReportApprover.Approve(model, sut); - } - - [Fact] - [MethodImpl(MethodImplOptions.NoInlining)] - public void TagsAreReportedInMarkdownReport() - { - var reportModel = this.CreateReportModel(); - var model = new FileReportModel(reportModel); - var sut = new MarkDownReportBuilder(); - ReportApprover.Approve(model, sut); - } - - private void GivenAStep() - { - - } - - private ReportModel CreateReportModel() - { - var story = this.Given(_ => GivenAStep()) - .WithTags("Tag1", "Tag 2") - .BDDfy(); - var reportModel = new[] { story }.ToReportModel(); - return reportModel; - } - } -} -#endif \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/TestStack.BDDfy.Tests.csproj b/src/TestStack.BDDfy.Tests/TestStack.BDDfy.Tests.csproj deleted file mode 100644 index e8cb18b0..00000000 --- a/src/TestStack.BDDfy.Tests/TestStack.BDDfy.Tests.csproj +++ /dev/null @@ -1,34 +0,0 @@ - - - net8.0 - TestStack.BDDfy.Tests - TestStack.BDDfy.Tests - true - false - false - false - false - false - false - - - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - diff --git a/src/TestStack.BDDfy.Tests/UnusedExampleValueScenario.cs b/src/TestStack.BDDfy.Tests/UnusedExampleValueScenario.cs deleted file mode 100644 index e2758b41..00000000 --- a/src/TestStack.BDDfy.Tests/UnusedExampleValueScenario.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Shouldly; -using TestStack.BDDfy.Processors; -using Xunit; - -namespace TestStack.BDDfy.Tests -{ - public class UnusedExampleValueScenario - { - [Fact] - public void WhenExampleIsNotUsedItThrows() - { - var ex = Should.Throw(() => - this.Given("Foo") - .WithExamples(new ExampleTable("Example 1") { 1 }).BDDfy()); - - ex.Message.ShouldBe("Example Column 'Example 1' is unused, all examples should be consumed by the test (have you misspelt a field or property?)\r\n\r\nIf this is not the case, raise an issue at https://github.com/TestStack/TestStack.BDDfy/issues."); - } - - [Fact] - public void NullableEnumIsUsedProperly() - { - SomeEnum? nullableEnum = null; - string anotherExample = null; - - this.Given(_ => GivenANullableEnumExample(nullableEnum)) - .Then(_ => AnotherValueIsChanged(anotherExample)) - .WithExamples(new ExampleTable("Nullable Enum", "Another Example") - { - {SomeEnum.Value, string.Empty}, - {null, string.Empty} - }) - .BDDfy(); - } - - private void AnotherValueIsChanged(string anotherExample) - { - } - - private void GivenANullableEnumExample(SomeEnum? nullableEnum) - { - } - - public enum SomeEnum - { - Value - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/WhenAnEmptyScenarioIsBddified.cs b/src/TestStack.BDDfy.Tests/WhenAnEmptyScenarioIsBddified.cs deleted file mode 100644 index d0013cef..00000000 --- a/src/TestStack.BDDfy.Tests/WhenAnEmptyScenarioIsBddified.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Xunit; - -namespace TestStack.BDDfy.Tests -{ - public class WhenAnEmptyScenarioIsBddified - { - private class ScenarioWithNoSteps - { - } - - [Fact] - public void ThenNoExeptionIsThrown() - { - new ScenarioWithNoSteps().BDDfy(); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.Tests/WhenAnEmptyStoryIsBddified.cs b/src/TestStack.BDDfy.Tests/WhenAnEmptyStoryIsBddified.cs deleted file mode 100644 index 5dbe0b76..00000000 --- a/src/TestStack.BDDfy.Tests/WhenAnEmptyStoryIsBddified.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Xunit; - -namespace TestStack.BDDfy.Tests -{ - [Story( - AsA = "As a programmer", - IWant = "I want to first create an empty story", - SoThat = "So that I can do test first development")] - public class WhenAnEmptyStoryIsBddified - { - [Fact] - public void NoExeptionIsThrown() - { - this.BDDfy(); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy.ncrunchsolution b/src/TestStack.BDDfy.ncrunchsolution deleted file mode 100644 index 5c74d788..00000000 --- a/src/TestStack.BDDfy.ncrunchsolution +++ /dev/null @@ -1,12 +0,0 @@ - - 1 - True - false - true - UseDynamicAnalysis - UseStaticAnalysis - UseStaticAnalysis - UseStaticAnalysis - - - \ No newline at end of file diff --git a/src/TestStack.BDDfy.sln b/src/TestStack.BDDfy.sln deleted file mode 100644 index ddf3f47b..00000000 --- a/src/TestStack.BDDfy.sln +++ /dev/null @@ -1,87 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 18 -VisualStudioVersion = 18.0.11018.127 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8F515887-AAB5-4873-8BE9-5AB10685EBCB}" - ProjectSection(SolutionItems) = preProject - .editorconfig = .editorconfig - ..\.gitattributes = ..\.gitattributes - ..\.gitignore = ..\.gitignore - ..\appveyor.deploy.yml = ..\appveyor.deploy.yml - ..\appveyor.yml = ..\appveyor.yml - ..\build.cake = ..\build.cake - ..\build.ps1 = ..\build.ps1 - ..\deploy.cake = ..\deploy.cake - ..\deploy.ps1 = ..\deploy.ps1 - Directory.build.props = Directory.build.props - ..\GitVersion.yml = ..\GitVersion.yml - ..\license.txt = ..\license.txt - ..\logo.png = ..\logo.png - ..\readme.md = ..\readme.md - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{AA78EE3D-14A7-47F0-85EF-4412F1514AE3}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestStack.BDDfy.Tests", "TestStack.BDDfy.Tests\TestStack.BDDfy.Tests.csproj", "{0D4A804C-C52D-4916-846B-D57B20322212}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestStack.BDDfy", "TestStack.BDDfy\TestStack.BDDfy.csproj", "{C1A46283-A5F2-4F93-9863-D731E5FC535B}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestStack.BDDfy.Samples", "Samples\TestStack.BDDfy.Samples\TestStack.BDDfy.Samples.csproj", "{267EA75C-EB57-4A15-80E7-9804A7B5F52B}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {0D4A804C-C52D-4916-846B-D57B20322212}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0D4A804C-C52D-4916-846B-D57B20322212}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0D4A804C-C52D-4916-846B-D57B20322212}.Debug|x64.ActiveCfg = Debug|Any CPU - {0D4A804C-C52D-4916-846B-D57B20322212}.Debug|x64.Build.0 = Debug|Any CPU - {0D4A804C-C52D-4916-846B-D57B20322212}.Debug|x86.ActiveCfg = Debug|Any CPU - {0D4A804C-C52D-4916-846B-D57B20322212}.Debug|x86.Build.0 = Debug|Any CPU - {0D4A804C-C52D-4916-846B-D57B20322212}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0D4A804C-C52D-4916-846B-D57B20322212}.Release|Any CPU.Build.0 = Release|Any CPU - {0D4A804C-C52D-4916-846B-D57B20322212}.Release|x64.ActiveCfg = Release|Any CPU - {0D4A804C-C52D-4916-846B-D57B20322212}.Release|x64.Build.0 = Release|Any CPU - {0D4A804C-C52D-4916-846B-D57B20322212}.Release|x86.ActiveCfg = Release|Any CPU - {0D4A804C-C52D-4916-846B-D57B20322212}.Release|x86.Build.0 = Release|Any CPU - {C1A46283-A5F2-4F93-9863-D731E5FC535B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C1A46283-A5F2-4F93-9863-D731E5FC535B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C1A46283-A5F2-4F93-9863-D731E5FC535B}.Debug|x64.ActiveCfg = Debug|Any CPU - {C1A46283-A5F2-4F93-9863-D731E5FC535B}.Debug|x64.Build.0 = Debug|Any CPU - {C1A46283-A5F2-4F93-9863-D731E5FC535B}.Debug|x86.ActiveCfg = Debug|Any CPU - {C1A46283-A5F2-4F93-9863-D731E5FC535B}.Debug|x86.Build.0 = Debug|Any CPU - {C1A46283-A5F2-4F93-9863-D731E5FC535B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C1A46283-A5F2-4F93-9863-D731E5FC535B}.Release|Any CPU.Build.0 = Release|Any CPU - {C1A46283-A5F2-4F93-9863-D731E5FC535B}.Release|x64.ActiveCfg = Release|Any CPU - {C1A46283-A5F2-4F93-9863-D731E5FC535B}.Release|x64.Build.0 = Release|Any CPU - {C1A46283-A5F2-4F93-9863-D731E5FC535B}.Release|x86.ActiveCfg = Release|Any CPU - {C1A46283-A5F2-4F93-9863-D731E5FC535B}.Release|x86.Build.0 = Release|Any CPU - {267EA75C-EB57-4A15-80E7-9804A7B5F52B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {267EA75C-EB57-4A15-80E7-9804A7B5F52B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {267EA75C-EB57-4A15-80E7-9804A7B5F52B}.Debug|x64.ActiveCfg = Debug|Any CPU - {267EA75C-EB57-4A15-80E7-9804A7B5F52B}.Debug|x64.Build.0 = Debug|Any CPU - {267EA75C-EB57-4A15-80E7-9804A7B5F52B}.Debug|x86.ActiveCfg = Debug|Any CPU - {267EA75C-EB57-4A15-80E7-9804A7B5F52B}.Debug|x86.Build.0 = Debug|Any CPU - {267EA75C-EB57-4A15-80E7-9804A7B5F52B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {267EA75C-EB57-4A15-80E7-9804A7B5F52B}.Release|Any CPU.Build.0 = Release|Any CPU - {267EA75C-EB57-4A15-80E7-9804A7B5F52B}.Release|x64.ActiveCfg = Release|Any CPU - {267EA75C-EB57-4A15-80E7-9804A7B5F52B}.Release|x64.Build.0 = Release|Any CPU - {267EA75C-EB57-4A15-80E7-9804A7B5F52B}.Release|x86.ActiveCfg = Release|Any CPU - {267EA75C-EB57-4A15-80E7-9804A7B5F52B}.Release|x86.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {267EA75C-EB57-4A15-80E7-9804A7B5F52B} = {AA78EE3D-14A7-47F0-85EF-4412F1514AE3} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {D9DD26E5-F04A-49BF-B9AA-68D5D17A8F36} - EndGlobalSection -EndGlobal diff --git a/src/TestStack.BDDfy.sln.DotSettings b/src/TestStack.BDDfy.sln.DotSettings deleted file mode 100644 index 04c2f043..00000000 --- a/src/TestStack.BDDfy.sln.DotSettings +++ /dev/null @@ -1,3 +0,0 @@ - - True - DO_NOT_SHOW \ No newline at end of file diff --git a/src/TestStack.BDDfy.v2.ncrunchsolution b/src/TestStack.BDDfy.v2.ncrunchsolution deleted file mode 100644 index 5c74d788..00000000 --- a/src/TestStack.BDDfy.v2.ncrunchsolution +++ /dev/null @@ -1,12 +0,0 @@ - - 1 - True - false - true - UseDynamicAnalysis - UseStaticAnalysis - UseStaticAnalysis - UseStaticAnalysis - - - \ No newline at end of file diff --git a/src/TestStack.BDDfy/BDDfyExtensions.cs b/src/TestStack.BDDfy/BDDfyExtensions.cs deleted file mode 100644 index 3340f3fa..00000000 --- a/src/TestStack.BDDfy/BDDfyExtensions.cs +++ /dev/null @@ -1,106 +0,0 @@ -using System; -using System.Linq; -using TestStack.BDDfy.Configuration; - -namespace TestStack.BDDfy -{ - public static class BDDfyExtensions - { -#if STACKTRACE - /// - /// Extension method to BDDfy an object instance. - /// - /// The test object representing a scenario. - /// Overrides the default scenario title and is displayed in the reports. - /// - public static Story BDDfy(this object testObject, string scenarioTitle = null) - { - return testObject.LazyBDDfy(scenarioTitle).Run(); - } - - public static Engine LazyBDDfy(this object testObject, string scenarioTitle = null) - { - return InternalLazyBDDfy(testObject, scenarioTitle); - } - - /// - /// Extension method to BDDfy an object instance. - /// - /// The type representing the story. - /// The test object representing a scenario. - /// Overrides the default scenario title and is displayed in the reports. - /// Caller (populated by [CallerMemberName]) - /// - public static Story BDDfy(this object testObject, string scenarioTitle = null) - where TStory : class - { - return InternalLazyBDDfy(testObject, scenarioTitle, typeof(TStory)).Run(); - } - - public static Engine LazyBDDfy(this object testObject, string scenarioTitle = null) - where TStory : class - { - return InternalLazyBDDfy(testObject, scenarioTitle, typeof(TStory)); - } -#else - /// - /// Extension method to BDDfy an object instance. - /// - /// The test object representing a scenario. - /// Overrides the default scenario title and is displayed in the reports. - /// Caller (populated by [CallerMemberName]) - /// - public static Story BDDfy(this object testObject, string scenarioTitle = null, [System.Runtime.CompilerServices.CallerMemberName] string caller = null) - { - return InternalLazyBDDfy(testObject, scenarioTitle ?? Configurator.Humanizer.Humanize(caller)).Run(); - } - - public static Engine LazyBDDfy(this object testObject, string scenarioTitle = null, [System.Runtime.CompilerServices.CallerMemberName] string caller = null) - { - return InternalLazyBDDfy(testObject, scenarioTitle ?? Configurator.Humanizer.Humanize(caller)); - } - - /// - /// Extension method to BDDfy an object instance. - /// - /// The type representing the story. - /// The test object representing a scenario. - /// Overrides the default scenario title and is displayed in the reports. - /// Caller (populated by [CallerMemberName]) - /// - public static Story BDDfy(this object testObject, string scenarioTitle = null, [System.Runtime.CompilerServices.CallerMemberName] string caller = null) - where TStory : class - { - return InternalLazyBDDfy(testObject, scenarioTitle ?? Configurator.Humanizer.Humanize(caller), typeof(TStory)).Run(); - } - - public static Engine LazyBDDfy(this object testObject, string scenarioTitle = null, [System.Runtime.CompilerServices.CallerMemberName] string caller = null) - where TStory : class - { - return InternalLazyBDDfy(testObject, scenarioTitle ?? Configurator.Humanizer.Humanize(caller), typeof(TStory)); - } -#endif - - static Engine InternalLazyBDDfy( - object testObject, - string scenarioTitle, - Type explicitStoryType = null) - { - var testContext = TestContext.GetContext(testObject); - - var storyScanner = testContext.FluentScanner != null ? - testContext.FluentScanner.GetScanner(scenarioTitle, explicitStoryType) : - GetReflectiveScanner(testContext, scenarioTitle, explicitStoryType); - - return new Engine(storyScanner); - } - - static IScanner GetReflectiveScanner(ITestContext testContext, string scenarioTitle = null, Type explicitStoryType = null) - { - var stepScanners = Configurator.Scanners.GetStepScanners(testContext).ToArray(); - var reflectiveScenarioScanner = new ReflectiveScenarioScanner(scenarioTitle, stepScanners); - - return new DefaultScanner(testContext, reflectiveScenarioScanner, explicitStoryType); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy/Configuration/BatchProcessorFactory.cs b/src/TestStack.BDDfy/Configuration/BatchProcessorFactory.cs deleted file mode 100644 index 45cccc5f..00000000 --- a/src/TestStack.BDDfy/Configuration/BatchProcessorFactory.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace TestStack.BDDfy.Configuration -{ - public class BatchProcessorFactory : ComponentFactory> - { - internal BatchProcessorFactory(Func factory) : base(factory) - { - } - - internal BatchProcessorFactory(Func factory, bool active) : base(factory, active) - { - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy/Configuration/BatchProcessors.cs b/src/TestStack.BDDfy/Configuration/BatchProcessors.cs deleted file mode 100644 index b90000cf..00000000 --- a/src/TestStack.BDDfy/Configuration/BatchProcessors.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using TestStack.BDDfy.Processors; -using TestStack.BDDfy.Reporters.Diagnostics; -using TestStack.BDDfy.Reporters.Html; -using TestStack.BDDfy.Reporters.MarkDown; - -namespace TestStack.BDDfy.Configuration -{ - public class BatchProcessors - { - IEnumerable _GetProcessors() - { - var htmlReporter = HtmlReport.ConstructFor(StoryCache.Stories); - if (htmlReporter != null) - yield return htmlReporter; - - var htmlMetroReporter = HtmlMetroReport.ConstructFor(StoryCache.Stories); - if (htmlMetroReporter != null) - yield return htmlMetroReporter; - - var markDown = MarkDownReport.ConstructFor(StoryCache.Stories); - if (markDown != null) - yield return markDown; - - var diagnostics = DiagnosticsReport.ConstructFor(StoryCache.Stories); - if (diagnostics != null) - yield return diagnostics; - - foreach (var addedProcessor in _addedProcessors) - { - yield return addedProcessor; - } - } - - private readonly BatchProcessorFactory _htmlReportFactory = new(() => new HtmlReporter(new DefaultHtmlReportConfiguration())); - public BatchProcessorFactory HtmlReport { get { return _htmlReportFactory; } } - - private readonly BatchProcessorFactory _htmlMetroReportFactory = new(() => new HtmlReporter(new DefaultHtmlReportConfiguration(), new MetroReportBuilder()), false); - public BatchProcessorFactory HtmlMetroReport { get { return _htmlMetroReportFactory; } } - - private readonly BatchProcessorFactory _markDownFactory = new(() => new MarkDownReporter(), false); - public BatchProcessorFactory MarkDownReport { get { return _markDownFactory; } } - - private readonly BatchProcessorFactory _diagnosticsFactory = new(() => new DiagnosticsReporter(), false); - public BatchProcessorFactory DiagnosticsReport { get { return _diagnosticsFactory; } } - - readonly List _addedProcessors = new(); - - public BatchProcessors Add(IBatchProcessor processor) - { - _addedProcessors.Add(processor); - return this; - } - - public IEnumerable GetProcessors() - { - return _GetProcessors().ToList(); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy/Configuration/ComponentFactory.cs b/src/TestStack.BDDfy/Configuration/ComponentFactory.cs deleted file mode 100644 index 8f5ed7ca..00000000 --- a/src/TestStack.BDDfy/Configuration/ComponentFactory.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; - -namespace TestStack.BDDfy.Configuration -{ - public class ComponentFactory where TComponent : class - { - private bool _active = true; - private Predicate _runsOn = o => true; - readonly Func _factory; - internal ComponentFactory(Func factory) - { - _factory = factory; - } - - internal ComponentFactory(Func factory, bool active) - { - _factory = factory; - _active = active; - } - - public void Disable() - { - _active = false; - } - - public void Enable() - { - _active = true; - } - - public TComponent ConstructFor(TMaterial material) - { - if (!_active || !_runsOn(material)) - return null; - - return _factory(); - } - - public void RunsOn(Predicate runOn) - { - _runsOn = runOn; - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy/Configuration/Configurator.cs b/src/TestStack.BDDfy/Configuration/Configurator.cs deleted file mode 100644 index 7ff99aef..00000000 --- a/src/TestStack.BDDfy/Configuration/Configurator.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace TestStack.BDDfy.Configuration -{ - public static class Configurator - { - public static bool AsyncVoidSupportEnabled { get; set; } = true; - - public static Processors Processors { get; } = new(); - - public static BatchProcessors BatchProcessors { get; } = new(); - - public static Scanners Scanners { get; } = new(); - - public static IKeyGenerator IdGenerator { get; set; } = new SequentialKeyGenerator(); - - public static IStepExecutor StepExecutor { get; set; } = new StepExecutor(); - - public static IHumanizer Humanizer { get; set; } = new DefaultHumanizer(); - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy/Configuration/HtmlReportFactory.cs b/src/TestStack.BDDfy/Configuration/HtmlReportFactory.cs deleted file mode 100644 index e9df6fc2..00000000 --- a/src/TestStack.BDDfy/Configuration/HtmlReportFactory.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Collections.Generic; -using TestStack.BDDfy.Processors; -using TestStack.BDDfy.Reporters.Html; - -namespace TestStack.BDDfy.Configuration -{ - public class HtmlReportFactory : ProcessorFactory - { - internal HtmlReportFactory(Func factory) : base(factory) - { - } - - public IEnumerable Configurations = - new IHtmlReportConfiguration[] - { - new DefaultHtmlReportConfiguration() - }; - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy/Configuration/IHumanizer.cs b/src/TestStack.BDDfy/Configuration/IHumanizer.cs deleted file mode 100644 index 02c4583c..00000000 --- a/src/TestStack.BDDfy/Configuration/IHumanizer.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace TestStack.BDDfy.Configuration -{ - public interface IHumanizer - { - string Humanize(string input); - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy/Configuration/IKeyGenerator.cs b/src/TestStack.BDDfy/Configuration/IKeyGenerator.cs deleted file mode 100644 index 10904c0f..00000000 --- a/src/TestStack.BDDfy/Configuration/IKeyGenerator.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace TestStack.BDDfy.Configuration -{ - public interface IKeyGenerator - { - string GetScenarioId(); - string GetStepId(); - void Reset(); - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy/Configuration/ProcessorFactory.cs b/src/TestStack.BDDfy/Configuration/ProcessorFactory.cs deleted file mode 100644 index 781418ad..00000000 --- a/src/TestStack.BDDfy/Configuration/ProcessorFactory.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; - -namespace TestStack.BDDfy.Configuration -{ - public class ProcessorFactory : ComponentFactory - { - internal ProcessorFactory(Func factory) : base(factory) - { - } - - internal ProcessorFactory(Func factory, bool active) : base(factory, active) - { - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy/Configuration/Processors.cs b/src/TestStack.BDDfy/Configuration/Processors.cs deleted file mode 100644 index f0dd03df..00000000 --- a/src/TestStack.BDDfy/Configuration/Processors.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using TestStack.BDDfy.Processors; -using TestStack.BDDfy.Reporters; - -namespace TestStack.BDDfy.Configuration -{ - public class Processors - { - IEnumerable _GetProcessors(Story story) - { - var runner = TestRunner.ConstructFor(story); - if (runner != null) - yield return runner; - - var consoleReporter = ConsoleReport.ConstructFor(story); - if (consoleReporter != null) - yield return consoleReporter; - - yield return new ExceptionProcessor(); - - var storyCache = StoryCache.ConstructFor(story); - if (storyCache != null) - yield return storyCache; - - yield return new Disposer(); - - foreach (var addedProcessor in _addedProcessors) - { - yield return addedProcessor(); - } - } - - public TestRunnerFactory TestRunner { get; } = new(() => new TestRunner()); - - public ProcessorFactory ConsoleReport { get; } = new(() => new ConsoleReporter()); - - public ProcessorFactory StoryCache { get; } = new(() => new StoryCache()); - - readonly List> _addedProcessors = []; - - public Processors Add(Func processorFactory) - { - _addedProcessors.Add(processorFactory); - return this; - } - - public IEnumerable GetProcessors(Story story) - { - var pipeline = from processor in _GetProcessors(story) - orderby processor.ProcessType - select processor; - - return pipeline.ToList(); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy/Configuration/Scanners.cs b/src/TestStack.BDDfy/Configuration/Scanners.cs deleted file mode 100644 index 22c2c845..00000000 --- a/src/TestStack.BDDfy/Configuration/Scanners.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace TestStack.BDDfy.Configuration -{ - public class Scanners - { - private readonly StepScannerFactory _executableAttributeScanner = new(() => new ExecutableAttributeStepScanner()); - public StepScannerFactory ExecutableAttributeScanner { get { return _executableAttributeScanner; } } - - private readonly StepScannerFactory _methodNameStepScanner = new(() => new DefaultMethodNameStepScanner()); - public StepScannerFactory DefaultMethodNameStepScanner { get { return _methodNameStepScanner; } } - - private readonly List> _addedStepScanners = new(); - public Scanners Add(Func stepScannerFactory) - { - _addedStepScanners.Add(stepScannerFactory); - return this; - } - - public IEnumerable GetStepScanners(object objectUnderTest) - { - var execAttributeScanner = ExecutableAttributeScanner.ConstructFor(objectUnderTest); - if (execAttributeScanner != null) - yield return execAttributeScanner; - - var defaultMethodNameScanner = DefaultMethodNameStepScanner.ConstructFor(objectUnderTest); - if (defaultMethodNameScanner != null) - yield return defaultMethodNameScanner; - - foreach (var addedStepScanner in _addedStepScanners) - { - yield return addedStepScanner(); - } - } - - public Func StoryMetadataScanner = () => new StoryAttributeMetadataScanner(); - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy/Configuration/SequentialKeyGenerator.cs b/src/TestStack.BDDfy/Configuration/SequentialKeyGenerator.cs deleted file mode 100644 index 56d522c4..00000000 --- a/src/TestStack.BDDfy/Configuration/SequentialKeyGenerator.cs +++ /dev/null @@ -1,29 +0,0 @@ -namespace TestStack.BDDfy.Configuration -{ - public class SequentialKeyGenerator : IKeyGenerator - { - private int _currentScenarioNumber = 1; - private int _currentStepNumber = 1; - - public string GetScenarioId() - { - var id = string.Format("scenario-{0}", _currentScenarioNumber); - _currentScenarioNumber++; - _currentStepNumber = 1; - return id; - } - - public string GetStepId() - { - var id = string.Format("step-{0}-{1}", _currentScenarioNumber, _currentStepNumber); - _currentStepNumber++; - return id; - } - - public void Reset() - { - _currentScenarioNumber = 1; - _currentStepNumber = 1; - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy/Configuration/StepScannerFactory.cs b/src/TestStack.BDDfy/Configuration/StepScannerFactory.cs deleted file mode 100644 index db4d6881..00000000 --- a/src/TestStack.BDDfy/Configuration/StepScannerFactory.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; - -namespace TestStack.BDDfy.Configuration -{ - public class StepScannerFactory : ComponentFactory - { - internal StepScannerFactory(Func factory) - : base(factory) - { - } - - internal StepScannerFactory(Func factory, bool active) - : base(factory, active) - { - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy/Configuration/TestRunnerFactory.cs b/src/TestStack.BDDfy/Configuration/TestRunnerFactory.cs deleted file mode 100644 index 9b082e24..00000000 --- a/src/TestStack.BDDfy/Configuration/TestRunnerFactory.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; - -namespace TestStack.BDDfy.Configuration -{ - public class TestRunnerFactory : ProcessorFactory - { - internal TestRunnerFactory(Func factory) : base(factory) - { - StopExecutionOnFailingThen = false; - } - - internal TestRunnerFactory(Func factory, bool active) : base(factory, active) - { - StopExecutionOnFailingThen = false; - } - - /// - /// Set to true if you want the execution pipleline to stop when a Then step fails. Defaulted to false - /// - public bool StopExecutionOnFailingThen { get; set; } - } -} diff --git a/src/TestStack.BDDfy/DateTimeExtensions.cs b/src/TestStack.BDDfy/DateTimeExtensions.cs deleted file mode 100644 index a20bc7aa..00000000 --- a/src/TestStack.BDDfy/DateTimeExtensions.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Globalization; - -namespace TestStack.BDDfy -{ - public static class DateTimeExtensions - { - public static string AsShortDateTimeString(this DateTime dateTime) - { - return dateTime.ToString(CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern); - } - } -} diff --git a/src/TestStack.BDDfy/DefaultHumanizer.cs b/src/TestStack.BDDfy/DefaultHumanizer.cs deleted file mode 100644 index 576ea423..00000000 --- a/src/TestStack.BDDfy/DefaultHumanizer.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text.RegularExpressions; -using System.Xml.Linq; -using TestStack.BDDfy.Configuration; - -namespace TestStack.BDDfy -{ - public partial class DefaultHumanizer: IHumanizer - { - static readonly Func FromUnderscoreSeparatedWords = methodName => string.Join(" ", methodName.Split(new[] { '_' })); - static string FromPascalCase(string name) - { - var chars = name.Aggregate( - new List(), - (list, currentChar) => - { - if (currentChar == ' ' || list.Count == 0) - list.Add(currentChar); - else - { - if(ShouldAddSpace(list[list.Count - 1], currentChar)) - list.Add(' '); - list.Add(char.ToLower(currentChar)); - } - - return list; - }); - - var result = new string(chars.ToArray()); - return result.Replace(" i ", " I "); // I is an exception - } - - private static bool ShouldAddSpace(char lastChar, char currentChar) - { - if (lastChar == ' ') - return false; - - if (char.IsDigit(lastChar)) - { - if (char.IsLetter(currentChar)) - return true; - - return false; - } - - if (!char.IsLower(currentChar) && currentChar != '>' && lastChar != '<') - return true; - - return false; - } - - private static readonly Func ConvertNonExample = name => { - if (name.Contains('_')) - return FromUnderscoreSeparatedWords(name); - - return FromPascalCase(name); - }; - - private string ExampleTitle(string name) - { - // Compare contains("__") with a regex match - string newName = TitleCleanerRegex().Replace(name, " <$1> "); - - if (newName == name) { - throw new ArgumentException("Illegal example title in name '" + name + "'!"); - } - - // for when there are two consequetive example placeholders in the word; e.g. Given__one____two__parameters - newName = newName.Replace(" ", " "); - return Humanize(newName).Trim(); - } - - public string Humanize(string input) - => input.Contains("__") ? ExampleTitle(input) : ConvertNonExample(input); - - [GeneratedRegex("__([a-zA-Z][a-zA-Z0-9]*)__")] - private static partial Regex TitleCleanerRegex(); - } -} diff --git a/src/TestStack.BDDfy/Engine.cs b/src/TestStack.BDDfy/Engine.cs deleted file mode 100644 index d29d4cf8..00000000 --- a/src/TestStack.BDDfy/Engine.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System.Linq; -using TestStack.BDDfy.Configuration; -using TestStack.BDDfy.Processors; - -namespace TestStack.BDDfy -{ - public class Engine(IScanner scanner) - { - private readonly IScanner _scanner = scanner; - - static Engine() - { -#if APPDOMAIN - System.AppDomain.CurrentDomain.DomainUnload += (sender, e) => { - InvokeBatchProcessors(); - }; -#else - System.Runtime.Loader.AssemblyLoadContext.Default.Unloading += context => InvokeBatchProcessors(); -#endif - } - - static void InvokeBatchProcessors() - { - foreach (var batchProcessor in Configurator.BatchProcessors.GetProcessors()) - { - batchProcessor.Process(StoryCache.Stories); - } - } - - public Story Run() - { - Story = _scanner.Scan(); - - var processors = Configurator.Processors.GetProcessors(Story).ToList(); - - try - { - //run processors in the right order regardless of the order they are provided to the Bddfier - foreach (var processor in processors.Where(p => p.ProcessType < ProcessType.Disposal).OrderBy(p => (int)p.ProcessType)) - processor.Process(Story); - } - finally - { - foreach (var finallyProcessor in processors.Where(p => p.ProcessType >= ProcessType.Disposal).OrderBy(p => (int)p.ProcessType)) - finallyProcessor.Process(Story); - } - - return Story; - } - - public Story Story { get; private set; } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy/ExecutionOrder.cs b/src/TestStack.BDDfy/ExecutionOrder.cs deleted file mode 100644 index 487e218d..00000000 --- a/src/TestStack.BDDfy/ExecutionOrder.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace TestStack.BDDfy -{ - public enum ExecutionOrder - { - Initialize = 1, - SetupState = 2, - ConsecutiveSetupState = 3, - Transition = 4, - ConsecutiveTransition = 5, - Assertion = 6, - ConsecutiveAssertion = 7, - TearDown = 8, - ConsecutiveStep - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy/IBatchProcessor.cs b/src/TestStack.BDDfy/IBatchProcessor.cs deleted file mode 100644 index 95d1dc65..00000000 --- a/src/TestStack.BDDfy/IBatchProcessor.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Collections.Generic; - -namespace TestStack.BDDfy -{ - public interface IBatchProcessor - { - void Process(IEnumerable stories); - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy/IProcessor.cs b/src/TestStack.BDDfy/IProcessor.cs deleted file mode 100644 index 3f8d7ec5..00000000 --- a/src/TestStack.BDDfy/IProcessor.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace TestStack.BDDfy -{ - public interface IProcessor - { - ProcessType ProcessType { get; } - void Process(Story story); - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy/IScanner.cs b/src/TestStack.BDDfy/IScanner.cs deleted file mode 100644 index 8a37b6f0..00000000 --- a/src/TestStack.BDDfy/IScanner.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace TestStack.BDDfy -{ - public interface IScanner - { - Story Scan(); - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy/IStepExecutor.cs b/src/TestStack.BDDfy/IStepExecutor.cs deleted file mode 100644 index c0979528..00000000 --- a/src/TestStack.BDDfy/IStepExecutor.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace TestStack.BDDfy -{ - public interface IStepExecutor - { - object Execute(Step step, object testObject); - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy/ITestContext.cs b/src/TestStack.BDDfy/ITestContext.cs deleted file mode 100644 index 2ad651f1..00000000 --- a/src/TestStack.BDDfy/ITestContext.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Collections.Generic; - -namespace TestStack.BDDfy -{ - public interface ITestContext - { - object TestObject { get; } - ExampleTable Examples { get; set; } - IFluentScanner FluentScanner { get; set; } - List Tags { get; } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy/ProcessType.cs b/src/TestStack.BDDfy/ProcessType.cs deleted file mode 100644 index 8e27e83e..00000000 --- a/src/TestStack.BDDfy/ProcessType.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace TestStack.BDDfy -{ - public enum ProcessType - { - Firstly = 1, - Execute = 2, - BeforeReport = 3, - Report = 4, - AfterReport = 5, - ProcessExceptions = 6, - Disposal = 7, - Finally = 8 - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy/Processors/AsyncTestRunner.cs b/src/TestStack.BDDfy/Processors/AsyncTestRunner.cs deleted file mode 100644 index 6d4b99e2..00000000 --- a/src/TestStack.BDDfy/Processors/AsyncTestRunner.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System; -using System.Security; -using System.Threading; -using System.Threading.Tasks; - -namespace TestStack.BDDfy.Processors -{ - public static class AsyncTestRunner - { - public static void Run(Func performStep) - { - var oldSyncContext = SynchronizationContext.Current; - try - { - var asyncSyncContext = new AsyncTestSyncContext(); - SetSynchronizationContext(asyncSyncContext); - var result = performStep(); - var task = result as Task; - if (task != null) - { - try - { - task.Wait(); - } - catch (AggregateException ae) - { - var innerException = ae.InnerException; - ExceptionProcessor.PreserveStackTrace(innerException); - throw innerException; - } - } - else - { - var ex = asyncSyncContext.WaitForCompletion(); - if (ex != null) - { - ExceptionProcessor.PreserveStackTrace(ex); - throw ex; - } - } - } - finally - { - SetSynchronizationContext(oldSyncContext); - } - } - - [SecuritySafeCritical] - private static void SetSynchronizationContext(SynchronizationContext context) - { - SynchronizationContext.SetSynchronizationContext(context); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy/Processors/AsyncTestSyncContext.cs b/src/TestStack.BDDfy/Processors/AsyncTestSyncContext.cs deleted file mode 100644 index ecdbfe62..00000000 --- a/src/TestStack.BDDfy/Processors/AsyncTestSyncContext.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System; -using System.Threading; - -namespace TestStack.BDDfy -{ - /// - /// Implementation from xUnit 2.0 - /// - internal class AsyncTestSyncContext : SynchronizationContext - { - readonly ManualResetEvent _event = new(initialState: true); - Exception _exception; - int _operationCount; - - public override void OperationCompleted() - { - var result = Interlocked.Decrement(ref _operationCount); - if (result == 0) - _event.Set(); - } - - public override void OperationStarted() - { - Interlocked.Increment(ref _operationCount); - _event.Reset(); - } - - public override void Post(SendOrPostCallback d, object state) - { - // The call to Post() may be the state machine signaling that an exception is - // about to be thrown, so we make sure the operation count gets incremented - // before the QUWI, and then decrement the count when the operation is done. - OperationStarted(); - - ThreadPool.QueueUserWorkItem(s => - { - try - { - Send(d, state); - } - finally - { - OperationCompleted(); - } - }); - } - - public override void Send(SendOrPostCallback d, object state) - { - try - { - d(state); - } - catch (Exception ex) - { - _exception = ex; - } - } - - public Exception WaitForCompletion() - { - _event.WaitOne(); - return _exception; - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy/Processors/Disposer.cs b/src/TestStack.BDDfy/Processors/Disposer.cs deleted file mode 100644 index 7e0479ad..00000000 --- a/src/TestStack.BDDfy/Processors/Disposer.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Linq; - -namespace TestStack.BDDfy.Processors -{ - public class Disposer : IProcessor - { - public ProcessType ProcessType - { - get { return ProcessType.Disposal; } - } - - public void Process(Story story) - { - foreach (var scenario in story.Scenarios) - { - Dispose(scenario); - } - } - - /// - /// Runs all the dispose methods in the scenario - /// - /// - private static void Dispose(Scenario scenario) - { - var disposeSteps = scenario - .Steps - .Where(s => s.ExecutionOrder == ExecutionOrder.TearDown && s.Result == Result.NotExecuted); - - var executor = new ScenarioExecutor(scenario); - - foreach (var disposeStep in disposeSteps) - executor.ExecuteStep(disposeStep); - } - - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy/Processors/ExceptionProcessor.cs b/src/TestStack.BDDfy/Processors/ExceptionProcessor.cs deleted file mode 100644 index 1df3d22a..00000000 --- a/src/TestStack.BDDfy/Processors/ExceptionProcessor.cs +++ /dev/null @@ -1,102 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; - -namespace TestStack.BDDfy.Processors -{ - public class ExceptionProcessor(Action assertInconclusive): IProcessor - { - private readonly Action _assertInconclusive = assertInconclusive; - private static readonly Action BestGuessInconclusiveAssertion; - - static readonly List ExcludedAssemblies = - new(new[] { "System", "mscorlib", "TestStack.BDDfy", "TestDriven", "JetBrains.ReSharper" }); - - static ExceptionProcessor() - { - var exceptionType = typeof(Exception); -// No best guess for CORE Clr -#if APPDOMAIN - foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) - { - if(ExcludedAssemblies.Any(ex => assembly.GetName().FullName.StartsWith(ex))) - continue; - - foreach (var inconclusiveExceptionType in GetTypesSafely(assembly)) - { - if (inconclusiveExceptionType.Name.Contains("Inconclusive") && - inconclusiveExceptionType.Name.Contains("Exception") && - exceptionType.IsAssignableFrom(inconclusiveExceptionType)) - { - var constructors = inconclusiveExceptionType.GetConstructors(); - var shortestCtor = constructors.Min(c => c.GetParameters().Length); - var ctor = constructors.First(c => c.GetParameters().Length == shortestCtor); - var argList = new List(); - argList.AddRange(ctor.GetParameters().Select(p => DefaultValue(p.ParameterType))); - BestGuessInconclusiveAssertion = () => { throw (Exception)ctor.Invoke(argList.ToArray()); }; - return; - } - } - } -#endif - - BestGuessInconclusiveAssertion = () => { throw new InconclusiveException(); }; - } - - private static IEnumerable GetTypesSafely(Assembly assembly) - { - try - { - return assembly.GetTypes(); - } - catch (ReflectionTypeLoadException ex) - { - return ex.Types.Where(x => x != null); - } - } - - //http://stackoverflow.com/questions/520290/how-can-i-get-the-default-value-of-a-type-in-a-non-generic-way - static object DefaultValue(Type myType) - { - return !myType.IsValueType() ? null : Activator.CreateInstance(myType); - } - - public ExceptionProcessor() : this(BestGuessInconclusiveAssertion) - { - } - - public ProcessType ProcessType - { - get { return ProcessType.ProcessExceptions; } - } - - // http://weblogs.asp.net/fmarguerie/archive/2008/01/02/rethrowing-exceptions-and-preserving-the-full-call-stack-trace.aspx - internal static void PreserveStackTrace(Exception exception) - { - MethodInfo preserveStackTrace = typeof(Exception).GetMethod("InternalPreserveStackTrace", - BindingFlags.Instance | BindingFlags.NonPublic); - preserveStackTrace.Invoke(exception, null); - } - - public void Process(Story story) - { - var allSteps = story.Scenarios.SelectMany(s => s.Steps); - if (!allSteps.Any()) - return; - - var worseResult = story.Result; - - var stepWithWorseResult = allSteps.First(s => s.Result == worseResult); - - if (worseResult == Result.Failed || worseResult == Result.Inconclusive) - { - PreserveStackTrace(stepWithWorseResult.Exception); - throw stepWithWorseResult.Exception; - } - - if (worseResult == Result.NotImplemented) - _assertInconclusive(); - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy/Processors/InconclusiveException.cs b/src/TestStack.BDDfy/Processors/InconclusiveException.cs deleted file mode 100644 index a0ee8841..00000000 --- a/src/TestStack.BDDfy/Processors/InconclusiveException.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Runtime.Serialization; - -namespace TestStack.BDDfy.Processors -{ - public class InconclusiveException : Exception - { - public InconclusiveException() - { - } - - public InconclusiveException(string message) : base(message) - { - } - - public InconclusiveException(string message, Exception innerException) : base(message, innerException) - { - } -#if NET40 - - protected InconclusiveException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } -#endif - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy/Processors/ScenarioExecutor.cs b/src/TestStack.BDDfy/Processors/ScenarioExecutor.cs deleted file mode 100644 index d69fb4f5..00000000 --- a/src/TestStack.BDDfy/Processors/ScenarioExecutor.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System; -using System.Linq; -using System.Reflection; -using TestStack.BDDfy.Configuration; - -namespace TestStack.BDDfy.Processors -{ - public class ScenarioExecutor(Scenario scenario) - { - private readonly Scenario _scenario = scenario; - - public void InitializeScenario() - { - if (_scenario.Example == null) - return; - - var type = _scenario.TestObject.GetType(); - var memberInfos = type - .GetMembers(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public) - .Where(m => m is FieldInfo || m is PropertyInfo) - .Where(m => !m.Name.EndsWith("BackingField")) - .ToArray(); - - var possibleTargets = memberInfos - .OfType() - .Select(f => new StepArgument(f.Name, f.FieldType, () => f.GetValue(_scenario.TestObject), o => f.SetValue(_scenario.TestObject, o))) - .Union(memberInfos.OfType().Select(m => new StepArgument(m.Name, m.PropertyType, () => m.GetValue(_scenario.TestObject, null), o => m.SetValue(_scenario.TestObject, o, null)))) - .Union(_scenario.Steps.SelectMany(s=>s.Arguments)) - .ToArray(); - - foreach (var cell in _scenario.Example.Values) - { - var matchingMembers = possibleTargets - .Where(n => cell.MatchesName(n.Name)) - .ToArray(); - - if (!matchingMembers.Any()) - continue; - - foreach (var matchingMember in matchingMembers) - { - matchingMember.SetValue(cell.GetValue(matchingMember.ArgumentType)); - } - } - } - - public Result ExecuteStep(Step step) - { - try - { - if (Configurator.AsyncVoidSupportEnabled) - AsyncTestRunner.Run(() => Configurator.StepExecutor.Execute(step, _scenario.TestObject)); - else - Configurator.StepExecutor.Execute(step, _scenario.TestObject); - step.Result = Result.Passed; - } - catch (Exception ex) - { - // ToDo: more thought should be put into this. Is it safe to get the exception? - var exception = ex; - if (exception is TargetInvocationException) - { - exception = ex.InnerException ?? ex; - } - - if (exception is NotImplementedException) - { - step.Result = Result.NotImplemented; - step.Exception = exception; - } - else if (IsInconclusive(exception)) - { - step.Result = Result.Inconclusive; - step.Exception = exception; - } - else - { - step.Exception = exception; - step.Result = Result.Failed; - } - } - - return step.Result; - } - - private static bool IsInconclusive(Exception exception) - { - return exception.GetType().Name.Contains("InconclusiveException"); - } - } -} diff --git a/src/TestStack.BDDfy/Processors/StoryCache.cs b/src/TestStack.BDDfy/Processors/StoryCache.cs deleted file mode 100644 index 0b0892ed..00000000 --- a/src/TestStack.BDDfy/Processors/StoryCache.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Collections.Generic; - -namespace TestStack.BDDfy.Processors -{ - public class StoryCache : IProcessor - { - private static readonly IList Cache = new List(); - - public ProcessType ProcessType - { - get { return ProcessType.Finally; } - } - - public void Process(Story story) - { - foreach (var scenario in story.Scenarios) - { - TestContext.ClearContextFor(scenario.TestObject); - scenario.TestObject = null; - foreach (var step in scenario.Steps) - step.Action = null; - } - - Cache.Add(story); - } - - public static IEnumerable Stories - { - get - { - return Cache; - } - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy/Processors/TestRunner.cs b/src/TestStack.BDDfy/Processors/TestRunner.cs deleted file mode 100644 index af0c2674..00000000 --- a/src/TestStack.BDDfy/Processors/TestRunner.cs +++ /dev/null @@ -1,47 +0,0 @@ -namespace TestStack.BDDfy.Processors -{ - using System.Linq; - - public class TestRunner : IProcessor - { - public ProcessType ProcessType - { - get { return ProcessType.Execute; } - } - - public void Process(Story story) - { - foreach (var scenario in story.Scenarios) - { - var executor = new ScenarioExecutor(scenario); - executor.InitializeScenario(); - - if (scenario.Example != null) - { - var unusedValue = scenario.Example.Values.FirstOrDefault(v => !v.ValueHasBeenUsed); - if (unusedValue != null) throw new UnusedExampleException(unusedValue); - } - - var stepFailed = false; - foreach (var executionStep in scenario.Steps) - { - if (stepFailed && ShouldExecuteStepWhenPreviousStepFailed(executionStep)) - break; - - if (executor.ExecuteStep(executionStep) == Result.Passed) - continue; - - if (!executionStep.Asserts) - break; - - stepFailed = true; - } - } - } - - private static bool ShouldExecuteStepWhenPreviousStepFailed(Step executionStep) - { - return Configuration.Configurator.Processors.TestRunner.StopExecutionOnFailingThen || !executionStep.Asserts; - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy/Processors/UnusedExampleException.cs b/src/TestStack.BDDfy/Processors/UnusedExampleException.cs deleted file mode 100644 index 4661af29..00000000 --- a/src/TestStack.BDDfy/Processors/UnusedExampleException.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; - -namespace TestStack.BDDfy.Processors -{ -#if NET40 - [System.Serializable] -#else - [System.Runtime.Serialization.Serializable] -#endif - public class UnusedExampleException(ExampleValue unusedValue): Exception(string.Format("Example Column '{0}' is unused, all examples should be consumed by the test (have you misspelt a field or property?)\r\n\r\n" - + "If this is not the case, raise an issue at https://github.com/TestStack/TestStack.BDDfy/issues.", unusedValue.Header)) - { -#if NET40 - - protected UnusedExampleException( - System.Runtime.Serialization.SerializationInfo info, - System.Runtime.Serialization.StreamingContext context) - : base(info, context) - { - } -#endif - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy/Properties/Annotations.cs b/src/TestStack.BDDfy/Properties/Annotations.cs deleted file mode 100644 index 027dcdcf..00000000 --- a/src/TestStack.BDDfy/Properties/Annotations.cs +++ /dev/null @@ -1,539 +0,0 @@ -using System; - -#pragma warning disable 1591 -// ReSharper disable UnusedMember.Global -// ReSharper disable UnusedParameter.Local -// ReSharper disable MemberCanBePrivate.Global -// ReSharper disable UnusedAutoPropertyAccessor.Global -// ReSharper disable IntroduceOptionalParameters.Global -// ReSharper disable MemberCanBeProtected.Global -// ReSharper disable InconsistentNaming - -namespace TestStack.BDDfy.Annotations -{ - /// - /// Indicates that the value of the marked element could be null sometimes, - /// so the check for null is necessary before its usage - /// - /// - /// [CanBeNull] public object Test() { return null; } - /// public void UseTest() { - /// var p = Test(); - /// var s = p.ToString(); // Warning: Possible 'System.NullReferenceException' - /// } - /// - [AttributeUsage( - AttributeTargets.Method | AttributeTargets.Parameter | - AttributeTargets.Property | AttributeTargets.Delegate | - AttributeTargets.Field, AllowMultiple = false, Inherited = true)] - public sealed class CanBeNullAttribute : Attribute { } - - /// - /// Indicates that the value of the marked element could never be null - /// - /// - /// [NotNull] public object Foo() { - /// return null; // Warning: Possible 'null' assignment - /// } - /// - [AttributeUsage( - AttributeTargets.Method | AttributeTargets.Parameter | - AttributeTargets.Property | AttributeTargets.Delegate | - AttributeTargets.Field, AllowMultiple = false, Inherited = true)] - public sealed class NotNullAttribute : Attribute { } - - /// - /// Indicates that the marked method builds string by format pattern and (optional) arguments. - /// Parameter, which contains format string, should be given in constructor. The format string - /// should be in -like form - /// - /// - /// [StringFormatMethod("message")] - /// public void ShowError(string message, params object[] args) { /* do something */ } - /// public void Foo() { - /// ShowError("Failed: {0}"); // Warning: Non-existing argument in format string - /// } - /// - /// - /// Specifies which parameter of an annotated method should be treated as format-string - /// - [AttributeUsage( - AttributeTargets.Constructor | AttributeTargets.Method, - AllowMultiple = false, Inherited = true)] - public sealed class StringFormatMethodAttribute(string formatParameterName): Attribute - { - public string FormatParameterName { get; private set; } = formatParameterName; - } - - /// - /// Indicates that the function argument should be string literal and match one - /// of the parameters of the caller function. For example, ReSharper annotates - /// the parameter of - /// - /// - /// public void Foo(string param) { - /// if (param == null) - /// throw new ArgumentNullException("par"); // Warning: Cannot resolve symbol - /// } - /// - [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)] - public sealed class InvokerParameterNameAttribute : Attribute { } - - /// - /// Indicates that the method is contained in a type that implements - /// interface - /// and this method is used to notify that some property value changed - /// - /// - /// The method should be non-static and conform to one of the supported signatures: - /// - /// NotifyChanged(string) - /// NotifyChanged(params string[]) - /// NotifyChanged{T}(Expression{Func{T}}) - /// NotifyChanged{T,U}(Expression{Func{T,U}}) - /// SetProperty{T}(ref T, T, string) - /// - /// - /// - /// public class Foo : INotifyPropertyChanged { - /// public event PropertyChangedEventHandler PropertyChanged; - /// [NotifyPropertyChangedInvocator] - /// protected virtual void NotifyChanged(string propertyName) { ... } - /// - /// private string _name; - /// public string Name { - /// get { return _name; } - /// set { _name = value; NotifyChanged("LastName"); /* Warning */ } - /// } - /// } - /// - /// Examples of generated notifications: - /// - /// NotifyChanged("Property") - /// NotifyChanged(() => Property) - /// NotifyChanged((VM x) => x.Property) - /// SetProperty(ref myField, value, "Property") - /// - /// - [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] - public sealed class NotifyPropertyChangedInvocatorAttribute : Attribute - { - public NotifyPropertyChangedInvocatorAttribute() { } - public NotifyPropertyChangedInvocatorAttribute(string parameterName) - { - ParameterName = parameterName; - } - - public string ParameterName { get; private set; } - } - - /// - /// Describes dependency between method input and output - /// - /// - ///

Function Definition Table syntax:

- /// - /// FDT ::= FDTRow [;FDTRow]* - /// FDTRow ::= Input => Output | Output <= Input - /// Input ::= ParameterName: Value [, Input]* - /// Output ::= [ParameterName: Value]* {halt|stop|void|nothing|Value} - /// Value ::= true | false | null | notnull | canbenull - /// - /// If method has single input parameter, it's name could be omitted.
- /// Using halt (or void/nothing, which is the same) - /// for method output means that the methos doesn't return normally.
- /// canbenull annotation is only applicable for output parameters.
- /// You can use multiple [ContractAnnotation] for each FDT row, - /// or use single attribute with rows separated by semicolon.
- ///
- /// - /// - /// [ContractAnnotation("=> halt")] - /// public void TerminationMethod() - /// - /// - /// [ContractAnnotation("halt <= condition: false")] - /// public void Assert(bool condition, string text) // regular assertion method - /// - /// - /// [ContractAnnotation("s:null => true")] - /// public bool IsNullOrEmpty(string s) // string.IsNullOrEmpty() - /// - /// - /// // A method that returns null if the parameter is null, and not null if the parameter is not null - /// [ContractAnnotation("null => null; notnull => notnull")] - /// public object Transform(object data) - /// - /// - /// [ContractAnnotation("s:null=>false; =>true,result:notnull; =>false, result:null")] - /// public bool TryParse(string s, out Person result) - /// - /// - [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)] - public sealed class ContractAnnotationAttribute([NotNull] string contract, bool forceFullStates): Attribute - { - public ContractAnnotationAttribute([NotNull] string contract) - : this(contract, false) { } - - public string Contract { get; private set; } = contract; - public bool ForceFullStates { get; private set; } = forceFullStates; - } - - /// - /// Indicates that marked element should be localized or not - /// - /// - /// [LocalizationRequiredAttribute(true)] - /// public class Foo { - /// private string str = "my string"; // Warning: Localizable string - /// } - /// - [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)] - public sealed class LocalizationRequiredAttribute(bool required): Attribute - { - public LocalizationRequiredAttribute() : this(true) { } - - public bool Required { get; private set; } = required; - } - - /// - /// Indicates that the value of the marked type (or its derivatives) - /// cannot be compared using '==' or '!=' operators and Equals() - /// should be used instead. However, using '==' or '!=' for comparison - /// with null is always permitted. - /// - /// - /// [CannotApplyEqualityOperator] - /// class NoEquality { } - /// class UsesNoEquality { - /// public void Test() { - /// var ca1 = new NoEquality(); - /// var ca2 = new NoEquality(); - /// if (ca1 != null) { // OK - /// bool condition = ca1 == ca2; // Warning - /// } - /// } - /// } - /// - [AttributeUsage( - AttributeTargets.Interface | AttributeTargets.Class | - AttributeTargets.Struct, AllowMultiple = false, Inherited = true)] - public sealed class CannotApplyEqualityOperatorAttribute : Attribute { } - - /// - /// When applied to a target attribute, specifies a requirement for any type marked - /// with the target attribute to implement or inherit specific type or types. - /// - /// - /// [BaseTypeRequired(typeof(IComponent)] // Specify requirement - /// public class ComponentAttribute : Attribute { } - /// [Component] // ComponentAttribute requires implementing IComponent interface - /// public class MyComponent : IComponent { } - /// - [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)] - [BaseTypeRequired(typeof(Attribute))] - public sealed class BaseTypeRequiredAttribute([NotNull] Type baseType): Attribute - { - [NotNull] public Type BaseType { get; private set; } = baseType; - } - - /// - /// Indicates that the marked symbol is used implicitly - /// (e.g. via reflection, in external library), so this symbol - /// will not be marked as unused (as well as by other usage inspections) - /// - [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)] - public sealed class UsedImplicitlyAttribute( - ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags): Attribute - { - public UsedImplicitlyAttribute() - : this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default) { } - - public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags) - : this(useKindFlags, ImplicitUseTargetFlags.Default) { } - - public UsedImplicitlyAttribute(ImplicitUseTargetFlags targetFlags) - : this(ImplicitUseKindFlags.Default, targetFlags) { } - - public ImplicitUseKindFlags UseKindFlags { get; private set; } = useKindFlags; - public ImplicitUseTargetFlags TargetFlags { get; private set; } = targetFlags; - } - - /// - /// Should be used on attributes and causes ReSharper - /// to not mark symbols marked with such attributes as unused - /// (as well as by other usage inspections) - /// - [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] - public sealed class MeansImplicitUseAttribute( - ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags): Attribute - { - public MeansImplicitUseAttribute() - : this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default) { } - - public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags) - : this(useKindFlags, ImplicitUseTargetFlags.Default) { } - - public MeansImplicitUseAttribute(ImplicitUseTargetFlags targetFlags) - : this(ImplicitUseKindFlags.Default, targetFlags) { } - - [UsedImplicitly] public ImplicitUseKindFlags UseKindFlags { get; private set; } = useKindFlags; - [UsedImplicitly] public ImplicitUseTargetFlags TargetFlags { get; private set; } = targetFlags; - } - - [Flags] - public enum ImplicitUseKindFlags - { - Default = Access | Assign | InstantiatedWithFixedConstructorSignature, - /// Only entity marked with attribute considered used - Access = 1, - /// Indicates implicit assignment to a member - Assign = 2, - /// - /// Indicates implicit instantiation of a type with fixed constructor signature. - /// That means any unused constructor parameters won't be reported as such. - /// - InstantiatedWithFixedConstructorSignature = 4, - /// Indicates implicit instantiation of a type - InstantiatedNoFixedConstructorSignature = 8, - } - - /// - /// Specify what is considered used implicitly - /// when marked with - /// or - /// - [Flags] - public enum ImplicitUseTargetFlags - { - Default = Itself, - Itself = 1, - /// Members of entity marked with attribute are considered used - Members = 2, - /// Entity marked with attribute and all its members considered used - WithMembers = Itself | Members - } - - /// - /// This attribute is intended to mark publicly available API - /// which should not be removed and so is treated as used - /// - [MeansImplicitUse] - public sealed class PublicAPIAttribute : Attribute - { - public PublicAPIAttribute() { } - public PublicAPIAttribute([NotNull] string comment) - { - Comment = comment; - } - - [NotNull] public string Comment { get; private set; } - } - - /// - /// Tells code analysis engine if the parameter is completely handled - /// when the invoked method is on stack. If the parameter is a delegate, - /// indicates that delegate is executed while the method is executed. - /// If the parameter is an enumerable, indicates that it is enumerated - /// while the method is executed - /// - [AttributeUsage(AttributeTargets.Parameter, Inherited = true)] - public sealed class InstantHandleAttribute : Attribute { } - - /// - /// Indicates that a method does not make any observable state changes. - /// The same as System.Diagnostics.Contracts.PureAttribute - /// - /// - /// [Pure] private int Multiply(int x, int y) { return x * y; } - /// public void Foo() { - /// const int a = 2, b = 2; - /// Multiply(a, b); // Waring: Return value of pure method is not used - /// } - /// - [AttributeUsage(AttributeTargets.Method, Inherited = true)] - public sealed class PureAttribute : Attribute { } - - /// - /// Indicates that a parameter is a path to a file or a folder - /// within a web project. Path can be relative or absolute, - /// starting from web root (~) - /// - [AttributeUsage(AttributeTargets.Parameter)] - public class PathReferenceAttribute : Attribute - { - public PathReferenceAttribute() { } - public PathReferenceAttribute([PathReference] string basePath) - { - BasePath = basePath; - } - - [NotNull] public string BasePath { get; private set; } - } - - /// - /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter - /// is an MVC action. If applied to a method, the MVC action name is calculated - /// implicitly from the context. Use this attribute for custom wrappers similar to - /// System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String) - /// - [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] - public sealed class AspMvcActionAttribute : Attribute - { - public AspMvcActionAttribute() { } - public AspMvcActionAttribute([NotNull] string anonymousProperty) - { - AnonymousProperty = anonymousProperty; - } - - [NotNull] public string AnonymousProperty { get; private set; } - } - - /// - /// ASP.NET MVC attribute. Indicates that a parameter is an MVC area. - /// Use this attribute for custom wrappers similar to - /// System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String) - /// - [AttributeUsage(AttributeTargets.Parameter)] - public sealed class AspMvcAreaAttribute : PathReferenceAttribute - { - public AspMvcAreaAttribute() { } - public AspMvcAreaAttribute([NotNull] string anonymousProperty) - { - AnonymousProperty = anonymousProperty; - } - - [NotNull] public string AnonymousProperty { get; private set; } - } - - /// - /// ASP.NET MVC attribute. If applied to a parameter, indicates that - /// the parameter is an MVC controller. If applied to a method, - /// the MVC controller name is calculated implicitly from the context. - /// Use this attribute for custom wrappers similar to - /// System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String, String) - /// - [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] - public sealed class AspMvcControllerAttribute : Attribute - { - public AspMvcControllerAttribute() { } - public AspMvcControllerAttribute([NotNull] string anonymousProperty) - { - AnonymousProperty = anonymousProperty; - } - - [NotNull] public string AnonymousProperty { get; private set; } - } - - /// - /// ASP.NET MVC attribute. Indicates that a parameter is an MVC Master. - /// Use this attribute for custom wrappers similar to - /// System.Web.Mvc.Controller.View(String, String) - /// - [AttributeUsage(AttributeTargets.Parameter)] - public sealed class AspMvcMasterAttribute : Attribute { } - - /// - /// ASP.NET MVC attribute. Indicates that a parameter is an MVC model type. - /// Use this attribute for custom wrappers similar to - /// System.Web.Mvc.Controller.View(String, Object) - /// - [AttributeUsage(AttributeTargets.Parameter)] - public sealed class AspMvcModelTypeAttribute : Attribute { } - - /// - /// ASP.NET MVC attribute. If applied to a parameter, indicates that - /// the parameter is an MVC partial view. If applied to a method, - /// the MVC partial view name is calculated implicitly from the context. - /// Use this attribute for custom wrappers similar to - /// System.Web.Mvc.Html.RenderPartialExtensions.RenderPartial(HtmlHelper, String) - /// - [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] - public sealed class AspMvcPartialViewAttribute : PathReferenceAttribute { } - - /// - /// ASP.NET MVC attribute. Allows disabling all inspections - /// for MVC views within a class or a method. - /// - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] - public sealed class AspMvcSupressViewErrorAttribute : Attribute { } - - /// - /// ASP.NET MVC attribute. Indicates that a parameter is an MVC display template. - /// Use this attribute for custom wrappers similar to - /// System.Web.Mvc.Html.DisplayExtensions.DisplayForModel(HtmlHelper, String) - /// - [AttributeUsage(AttributeTargets.Parameter)] - public sealed class AspMvcDisplayTemplateAttribute : Attribute { } - - /// - /// ASP.NET MVC attribute. Indicates that a parameter is an MVC editor template. - /// Use this attribute for custom wrappers similar to - /// System.Web.Mvc.Html.EditorExtensions.EditorForModel(HtmlHelper, String) - /// - [AttributeUsage(AttributeTargets.Parameter)] - public sealed class AspMvcEditorTemplateAttribute : Attribute { } - - /// - /// ASP.NET MVC attribute. Indicates that a parameter is an MVC template. - /// Use this attribute for custom wrappers similar to - /// System.ComponentModel.DataAnnotations.UIHintAttribute(System.String) - /// - [AttributeUsage(AttributeTargets.Parameter)] - public sealed class AspMvcTemplateAttribute : Attribute { } - - /// - /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter - /// is an MVC view. If applied to a method, the MVC view name is calculated implicitly - /// from the context. Use this attribute for custom wrappers similar to - /// System.Web.Mvc.Controller.View(Object) - /// - [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] - public sealed class AspMvcViewAttribute : PathReferenceAttribute { } - - /// - /// ASP.NET MVC attribute. When applied to a parameter of an attribute, - /// indicates that this parameter is an MVC action name - /// - /// - /// [ActionName("Foo")] - /// public ActionResult Login(string returnUrl) { - /// ViewBag.ReturnUrl = Url.Action("Foo"); // OK - /// return RedirectToAction("Bar"); // Error: Cannot resolve action - /// } - /// - [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property)] - public sealed class AspMvcActionSelectorAttribute : Attribute { } - - [AttributeUsage( - AttributeTargets.Parameter | AttributeTargets.Property | - AttributeTargets.Field, Inherited = true)] - public sealed class HtmlElementAttributesAttribute : Attribute - { - public HtmlElementAttributesAttribute() { } - public HtmlElementAttributesAttribute([NotNull] string name) - { - Name = name; - } - - [NotNull] public string Name { get; private set; } - } - - [AttributeUsage( - AttributeTargets.Parameter | AttributeTargets.Field | - AttributeTargets.Property, Inherited = true)] - public sealed class HtmlAttributeValueAttribute([NotNull] string name): Attribute - { - [NotNull] public string Name { get; private set; } = name; - } - - // Razor attributes - - /// - /// Razor attribute. Indicates that a parameter or a method is a Razor section. - /// Use this attribute for custom wrappers similar to - /// System.Web.WebPages.WebPageBase.RenderSection(String) - /// - [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method, Inherited = true)] - public sealed class RazorSectionAttribute : Attribute { } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy/Properties/AssemblyInfo.cs b/src/TestStack.BDDfy/Properties/AssemblyInfo.cs deleted file mode 100644 index 46b351b7..00000000 --- a/src/TestStack.BDDfy/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("TestStack.BDDfy - http://teststack.github.com/TestStack.BDDfy/")] -[assembly: AssemblyProduct("TestStack.BDDfy")] -[assembly: AssemblyCopyright("Copyright © 2011-2017 TestStack.BDDfy contributors")] -[assembly: AssemblyTrademark("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("20482e5c-b996-4cc8-b30b-fc7b16268b29")] \ No newline at end of file diff --git a/src/TestStack.BDDfy/Reporters/ConsoleReporter.cs b/src/TestStack.BDDfy/Reporters/ConsoleReporter.cs deleted file mode 100644 index 1ef9c97c..00000000 --- a/src/TestStack.BDDfy/Reporters/ConsoleReporter.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; - -namespace TestStack.BDDfy.Reporters -{ - public class ConsoleReporter : TextReporter - { - protected override void Write(string text, params object[] args) - { - Console.Write(text, args); - } - - protected override void WriteLine(string text = null) - { - Console.WriteLine(text); - } - - protected override void WriteLine(string text, params object[] args) - { - Console.WriteLine(text, args); - } - - public override ConsoleColor ForegroundColor - { - get { return Console.ForegroundColor; } - set { Console.ForegroundColor = value; } - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy/Reporters/Diagnostics/DiagnosticsReport.cs b/src/TestStack.BDDfy/Reporters/Diagnostics/DiagnosticsReport.cs deleted file mode 100644 index eff9673a..00000000 --- a/src/TestStack.BDDfy/Reporters/Diagnostics/DiagnosticsReport.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Collections.Generic; - -namespace TestStack.BDDfy.Reporters.Diagnostics -{ - public class DiagnosticsReport - { - public IList Stories { get; set; } - } -} diff --git a/src/TestStack.BDDfy/Reporters/Diagnostics/DiagnosticsReportBuilder.cs b/src/TestStack.BDDfy/Reporters/Diagnostics/DiagnosticsReportBuilder.cs deleted file mode 100644 index 765f34ad..00000000 --- a/src/TestStack.BDDfy/Reporters/Diagnostics/DiagnosticsReportBuilder.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using TestStack.BDDfy.Reporters.Serializers; - -namespace TestStack.BDDfy.Reporters.Diagnostics -{ - public class DiagnosticsReportBuilder(ISerializer serializer): IReportBuilder - { - private readonly ISerializer _serializer = serializer; - - public DiagnosticsReportBuilder() : this(new JsonSerializer()) { } - - public string CreateReport(FileReportModel model) - { - var graph = GetDiagnosticData(model); - var rootObject = new DiagnosticsReport { Stories = graph }; - return _serializer.Serialize(rootObject); - } - - public IList GetDiagnosticData(FileReportModel viewModel) - { - var graph = new List(); - foreach (var story in viewModel.Stories) - { - var name = story.Namespace; - if (story.Metadata != null) - name = story.Metadata.Title; - - graph.Add(new StoryDiagnostic - { - Name = name, - Duration = story.Scenarios.Sum(x => x.Duration.Milliseconds), - Scenarios = story.Scenarios.Select(scenario => new StoryDiagnostic.Scenario() - { - Name = scenario.Title, - Duration = scenario.Duration.Milliseconds, - Steps = scenario.Steps.Select(step => new StoryDiagnostic.Step() - { - Name = step.Title, - Duration = step.Duration.Milliseconds - }).ToList() - }).ToList() - }); - } - - return graph; - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy/Reporters/Diagnostics/DiagnosticsReporter.cs b/src/TestStack.BDDfy/Reporters/Diagnostics/DiagnosticsReporter.cs deleted file mode 100644 index 1b4646b3..00000000 --- a/src/TestStack.BDDfy/Reporters/Diagnostics/DiagnosticsReporter.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Collections.Generic; -using TestStack.BDDfy.Reporters.Writers; - -namespace TestStack.BDDfy.Reporters.Diagnostics -{ - public class DiagnosticsReporter(IReportBuilder builder, IReportWriter writer): IBatchProcessor - { - private readonly IReportBuilder _builder = builder; - private readonly IReportWriter _writer = writer; - - public DiagnosticsReporter() : this(new DiagnosticsReportBuilder(), new FileWriter()) { } - - public void Process(IEnumerable stories) - { - var viewModel = new FileReportModel(stories.ToReportModel()); - string report; - - try - { - report = _builder.CreateReport(viewModel); - } - catch (Exception ex) - { - report = ex.Message + ex.StackTrace; - } - - _writer.OutputReport(report, "Diagnostics.json"); - } - } -} diff --git a/src/TestStack.BDDfy/Reporters/Diagnostics/StoryDiagnostic.cs b/src/TestStack.BDDfy/Reporters/Diagnostics/StoryDiagnostic.cs deleted file mode 100644 index 95eebfc5..00000000 --- a/src/TestStack.BDDfy/Reporters/Diagnostics/StoryDiagnostic.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Collections.Generic; - -namespace TestStack.BDDfy.Reporters.Diagnostics -{ - public class StoryDiagnostic - { - public string Name { get; set; } - public int Duration { get; set; } - public List Scenarios { get; set; } - - public class Scenario - { - public string Name { get; set; } - public int Duration { get; set; } - public List Steps { get; set; } - } - - public class Step - { - public string Name { get; set; } - public int Duration { get; set; } - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy/Reporters/FileHelpers.cs b/src/TestStack.BDDfy/Reporters/FileHelpers.cs deleted file mode 100644 index 58c55259..00000000 --- a/src/TestStack.BDDfy/Reporters/FileHelpers.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.IO; - -namespace TestStack.BDDfy.Reporters -{ - public class FileHelpers - { - // http://stackoverflow.com/questions/52797/c-how-do-i-get-the-path-of-the-assembly-the-code-is-in#answer-283917 - internal static string AssemblyDirectory() - { -#if NET40 - string codeBase = typeof(Engine).Assembly().CodeBase; - var uri = new UriBuilder(codeBase); - string path = Uri.UnescapeDataString(uri.Path); - return Path.GetDirectoryName(path); -#else - var basePath = AppContext.BaseDirectory; - return Path.GetFullPath(basePath); -#endif - } - - } -} diff --git a/src/TestStack.BDDfy/Reporters/FileReportModel.cs b/src/TestStack.BDDfy/Reporters/FileReportModel.cs deleted file mode 100644 index 8b50e30c..00000000 --- a/src/TestStack.BDDfy/Reporters/FileReportModel.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace TestStack.BDDfy.Reporters -{ - public class FileReportModel(ReportModel reportModel) - { - readonly IEnumerable _stories = reportModel.Stories; - public FileReportSummaryModel Summary { get; private set; } = new FileReportSummaryModel(reportModel); - public DateTime RunDate { get; set; } = DateTime.Now; - - public IEnumerable Stories - { - get - { - var groupedByNamespace = from story in _stories - where story.Metadata == null - orderby story.Namespace - group story by story.Namespace into g - select g; - - var groupedByStories = from story in _stories - where story.Metadata != null - orderby story.Metadata.Title - group story by story.Metadata.Type.Name into g - select g; - - var aggregatedStories = - from story in groupedByStories.Union(groupedByNamespace) - select new ReportModel.Story() - { - Metadata = story.First().Metadata, - Namespace = story.Key, - Result = story.First().Result, - Scenarios = story.SelectMany(s => s.Scenarios).OrderBy(s => s.Title).ToList() // order scenarios by title, - }; - - return aggregatedStories; - } - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy/Reporters/FileReportSummaryModel.cs b/src/TestStack.BDDfy/Reporters/FileReportSummaryModel.cs deleted file mode 100644 index 80d0e91a..00000000 --- a/src/TestStack.BDDfy/Reporters/FileReportSummaryModel.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -namespace TestStack.BDDfy.Reporters -{ - public class FileReportSummaryModel - { - readonly IEnumerable _stories; - readonly IEnumerable _scenarios; - - public FileReportSummaryModel(ReportModel reportModel) - { - _stories = reportModel.Stories; - _scenarios = _stories.SelectMany(s => s.Scenarios).ToList(); - } - - public int Namespaces - { - get - { - return _stories.Where(b => b.Metadata == null).GroupBy(s => s.Namespace).Count(); - } - } - - public int Scenarios - { - get { return _stories.SelectMany(s => s.Scenarios).Count(); } - } - - public int Stories - { - get { return _stories.Where(b => b.Metadata != null).GroupBy(b => b.Metadata.Type).Count(); } - } - - public int Passed - { - get { return _scenarios.Count(b => b.Result == Result.Passed); } - } - - public int Failed - { - get { return _scenarios.Count(b => b.Result == Result.Failed); } - } - - public int Inconclusive - { - get { return _scenarios.Count(b => b.Result == Result.Inconclusive); } - } - - public int NotImplemented - { - get { return _scenarios.Count(b => b.Result == Result.NotImplemented); } - } - } -} \ No newline at end of file diff --git a/src/TestStack.BDDfy/Reporters/Html/ClassicReportBuilder.cs b/src/TestStack.BDDfy/Reporters/Html/ClassicReportBuilder.cs deleted file mode 100644 index 32504488..00000000 --- a/src/TestStack.BDDfy/Reporters/Html/ClassicReportBuilder.cs +++ /dev/null @@ -1,397 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Text; -using TestStack.BDDfy.Configuration; - -namespace TestStack.BDDfy.Reporters.Html -{ - public class ClassicReportBuilder : IReportBuilder - { - private HtmlReportModel _model; - readonly StringBuilder _html; - const int TabIndentation = 2; - int _tabCount; - - public ClassicReportBuilder() - { - _html = new StringBuilder(); - } - - string IReportBuilder.CreateReport(FileReportModel model) - { - return CreateReport(model as HtmlReportModel); - } - - public string CreateReport(HtmlReportModel model) - { - _model = model; - AddLine(""); - using (OpenTag(HtmlTag.html)) - { - HtmlHead(); - HtmlBody(); - } - - return _html.ToString(); - } - - private void HtmlHead() - { - using (OpenTag(HtmlTag.head)) - { - AddLine(""); - EmbedCssFile(HtmlReportResources.classic_css_min); - EmbedCssFile(_model.CustomStylesheet, HtmlReportResources.CustomStylesheetComment); - - AddLine(string.Format("BDDfy Test Result {0}", _model.RunDate.AsShortDateTimeString())); - } - } - - private void HtmlBody() - { - using (OpenTag(HtmlTag.body)) - { - using (OpenTag("
", HtmlTag.div)) - { - Header(); - ResultSummary(); - ResultDetails(); - } - - Footer(); - } - } - - private void Header() - { - using (OpenTag("
", HtmlTag.div)) - { - AddLine(string.Format("
{0}
", _model.Configuration.ReportHeader)); - AddLine(string.Format("
{0}
", _model.Configuration.ReportDescription)); - } - } - - private void ResultSummary() - { - using (OpenTag("
", HtmlTag.section)) - { - AddLine("

Summary:

"); - - using (OpenTag("
    ", HtmlTag.ul)) - { - AddSummaryLine("storySummary", "Stories", _model.Summary.Stories); - AddSummaryLine("scenarioSummary", "Scenarios", _model.Summary.Scenarios); - AddSummaryLine("Passed", "Passed", _model.Summary.Passed); - AddSummaryLine("Inconclusive", "Inconclusive", _model.Summary.Inconclusive); - AddSummaryLine("NotImplemented", "Not Implemented", _model.Summary.NotImplemented); - AddSummaryLine("Failed", "Failed", _model.Summary.Failed); - } - } - } - - private void AddSummaryLine(string cssClass, string label, int count) - { - using (OpenTag(string.Format("
  • ", cssClass), HtmlTag.li)) - { - using (OpenTag("
    ", HtmlTag.div)) - { - AddLine(string.Format("
    {0}
    ", label)); - AddLine(string.Format("{0}", count)); - } - } - } - - private void ExpandCollapse() - { - using (OpenTag("
    ", HtmlTag.div)) - { - AddLine("[expand all]"); - AddLine("[collapse all]"); - } - } - - private void ResultDetails() - { - using (OpenTag("
    ", HtmlTag.div)) - { - using (OpenTag("
    ", HtmlTag.div)) - { - AddLine("

    Details:

    "); - - ExpandCollapse(); - } - - using (OpenTag("
      ", HtmlTag.ul)) - { - foreach (var story in _model.Stories) - { - AddStory(story); - } - } - - AddLine(string.Format("

      Tested at: {0}

      ", _model.RunDate)); - } - } - - private void Footer() - { - AddLine(""); - - if (_model.Configuration.ResolveJqueryFromCdn) - AddLine(""); - else - EmbedJavascriptFile(HtmlReportResources.jquery_2_1_0_min); - - EmbedJavascriptFile(HtmlReportResources.classic_js_min); - EmbedJavascriptFile(_model.CustomJavascript, HtmlReportResources.CustomJavascriptComment); - } - - private void AddStory(ReportModel.Story story) - { - var scenariosInGroup = story.Scenarios.ToList(); - var scenariosGroupedById = story.Scenarios.GroupBy(s => s.Id); - var storyResult = (Result)scenariosInGroup.Max(s => (int)s.Result); - - using (OpenTag(HtmlTag.li)) - { - using (OpenTag(string.Format("
      ", storyResult), HtmlTag.div)) - { - AddStoryMetadataAndNarrative(story); - - using (OpenTag("
      ", HtmlTag.div)) - { - foreach (var scenario in scenariosGroupedById) - { - AddScenario(scenario.ToArray()); - } - } - } - } - } - - private void AddScenario(ReportModel.Scenario[] scenarioGroup) - { - using (OpenTag(string.Format("
      "), HtmlTag.div)) - { - if (scenarioGroup.First().Example == null) - AddScenario(scenarioGroup.Single()); - else - AddScenarioWithExamples(scenarioGroup); - } - } - - private void AddScenarioWithExamples(ReportModel.Scenario[] scenarioGroup) - { - var firstScenario = scenarioGroup.First(); - var scenarioResult = (Result)scenarioGroup.Max(s => (int)s.Result); - - AddLine(string.Format("
      {2}{3}
      ", scenarioResult, firstScenario.Id, WebUtility.HtmlEncode(firstScenario.Title), FormatTags(firstScenario.Tags))); - - using (OpenTag(string.Format("
        ", firstScenario.Id), HtmlTag.ul)) - { - foreach (var step in firstScenario.Steps.Where(s => s.ShouldReport)) - { - using (OpenTag(string.Format("
      • ", step.ExecutionOrder), HtmlTag.li)) - { - var titleLines = WebUtility.HtmlEncode(step.Title) - .Split(new[] { Environment.NewLine }, StringSplitOptions.None); - var title = titleLines[0]; - - AddLine(string.Format("{0}", title)); - - for (int i = 1; i < titleLines.Length; i++) - AddLine(string.Format("
        {0}
        ", titleLines[i])); - } - } - - AddExamples(scenarioGroup); - } - } - - private string FormatTags(List tags) - { - return string.Join(string.Empty, tags.Select(t => string.Format("
        {0}
        ", t))); - } - - private void AddExamples(ReportModel.Scenario[] scenarioGroup) - { - var firstScenario = scenarioGroup.First(); - var scenarioResult = (Result)scenarioGroup.Max(s => (int)s.Result); - - using (OpenTag("
      • ", HtmlTag.li)) - { - AddLine("Examples:"); - using (OpenTag(string.Format(""), HtmlTag.table)) - { - using (OpenTag("", HtmlTag.tr)) - { - AddLine(string.Format("")); - foreach (var header in firstScenario.Example.Headers) - AddLine(string.Format("", header)); - - if (scenarioResult == Result.Failed) - AddLine(string.Format("")); - } - - foreach (var scenario in scenarioGroup) - AddExampleRow(scenario, scenarioResult); - } - } - } - - private void AddExampleRow(ReportModel.Scenario scenario, Result scenarioResult) - { - using (OpenTag("", HtmlTag.tr)) - { - AddLine(string.Format("", scenario.Result)); - foreach (var exampleValue in scenario.Example.Values) - AddLine(string.Format("", WebUtility.HtmlEncode(exampleValue.GetValueAsString()))); - - if (scenarioResult != Result.Failed) - return; - - using (OpenTag("
        {0}Error
        {0}", HtmlTag.td)) - { - var failingStep = scenario.Steps.FirstOrDefault(s => s.Result == Result.Failed); - - if (failingStep == null) - return; - - var exceptionId = Configurator.IdGenerator.GetStepId(); - var encodedExceptionMessage = WebUtility.HtmlEncode(failingStep.Exception.Message); - AddLine(string.Format("{1}", exceptionId, encodedExceptionMessage)); - using (OpenTag(string.Format("
        ", exceptionId), HtmlTag.div)) - { - AddLine(string.Format("{0}", failingStep.Exception.StackTrace)); - } - } - } - } - - private void AddScenario(ReportModel.Scenario scenario) - { - AddLine(string.Format("
        {2}{3}
        ", scenario.Result, scenario.Id, scenario.Title, FormatTags(scenario.Tags))); - - using (OpenTag(string.Format("
          ", scenario.Id), HtmlTag.ul)) - { - foreach (var step in scenario.Steps.Where(s => s.ShouldReport)) - { - string stepClass = string.Empty; - var reportException = step.Exception != null && step.Result == Result.Failed; - string canToggle = reportException ? "canToggle" : string.Empty; - - using (OpenTag(string.Format("
        • ", step.Result, stepClass, step.ExecutionOrder, canToggle, step.Id), HtmlTag.li)) - { - var titleLines = step.Title.Split(new[] { Environment.NewLine }, StringSplitOptions.None); - var title = titleLines[0]; - if (reportException) - { - stepClass = step.Result + "Exception"; - if (!string.IsNullOrEmpty(step.Exception.Message)) - title += " [Exception Message: '" + step.Exception.Message + "']"; - } - - AddLine(string.Format("{0}", title)); - - for (int i = 1; i < titleLines.Length; i++) - AddLine(string.Format("
          {0}
          ", titleLines[i])); - - if (reportException) - { - using (OpenTag(string.Format("
          ", stepClass, step.Id), HtmlTag.div)) - { - AddLine(string.Format("{0}", step.Exception.StackTrace)); - } - } - } - } - } - } - - private void AddStoryMetadataAndNarrative(ReportModel.Story story) - { - using (OpenTag("