├── .github
└── workflows
│ ├── dotnet6.yml
│ ├── dotnet6noartifacts.yml
│ └── dotnet7.yml
├── .gitignore
├── LICENSE.md
├── README.md
├── RunSpecflowTests.sln
├── RunSpecflowTests
├── Features
│ └── Calculator.feature
├── RunSpecflowTests.csproj
└── Steps
│ └── CalculatorStepDefinitions.cs
└── action.yml
/.github/workflows/dotnet6.yml:
--------------------------------------------------------------------------------
1 | name: .NET 6.0
2 | on:
3 | push:
4 |
5 | jobs:
6 | build:
7 | name: Build & Test
8 | runs-on: ubuntu-latest
9 |
10 | steps:
11 | - name: Checkout
12 | uses: actions/checkout@v4
13 | - name: Setup .NET
14 | uses: actions/setup-dotnet@v4
15 | with:
16 | dotnet-version: 6.0.x
17 | - uses: ./
18 | with:
19 | test-assembly-path: RunSpecflowTests/bin/Release/net6.0
20 | test-assembly-dll: RunSpecflowTests.dll
21 | output-html: CalculatorResults.html
22 | framework: net6.0
--------------------------------------------------------------------------------
/.github/workflows/dotnet6noartifacts.yml:
--------------------------------------------------------------------------------
1 | name: .NET 6.0 No Artifacts
2 | on:
3 | push:
4 |
5 | jobs:
6 | build:
7 | name: Build & Test
8 | runs-on: ubuntu-latest
9 |
10 | steps:
11 | - name: Checkout
12 | uses: actions/checkout@v4
13 | - name: Setup .NET
14 | uses: actions/setup-dotnet@v4
15 | with:
16 | dotnet-version: 6.0.x
17 | - uses: ./
18 | with:
19 | test-assembly-path: RunSpecflowTests/bin/Release/net6.0
20 | test-assembly-dll: RunSpecflowTests.dll
21 | output-html: CalculatorResults.html
22 | framework: net6.0
23 | upload-artifact: false
24 |
--------------------------------------------------------------------------------
/.github/workflows/dotnet7.yml:
--------------------------------------------------------------------------------
1 | name: .NET 7.0
2 | on:
3 | push:
4 |
5 | jobs:
6 | build:
7 | name: Build & Test
8 | runs-on: ubuntu-latest
9 |
10 | steps:
11 | - name: Checkout
12 | uses: actions/checkout@v4
13 | - name: Setup .NET Core
14 | uses: actions/setup-dotnet@v4
15 | with:
16 | dotnet-version: 7.0.x
17 | - uses: ./
18 | with:
19 | test-assembly-dll: RunSpecflowTests/bin/Debug/net7.0/RunSpecflowTests.dll
20 | test-execution-json: RunSpecflowTests/bin/Debug/net7.0/TestExecution.json
21 | output-html: CalculatorResults.html
22 | filter: 'FullyQualifiedName~Calculator'
23 | framework: net7.0
24 | configuration: 'Debug'
25 | logger: trx
26 | logger-file-name: ../../CalculatorResults.trx
27 | - name: Publish Specflow Test Logs
28 | if: success() || failure()
29 | uses: actions/upload-artifact@v4
30 | with:
31 | name: SpecflowLogs
32 | path: |
33 | CalculatorResults.trx
34 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled C#
2 | */bin
3 | */obj
4 |
5 | # Compiled Specflow
6 | *.feature.cs
7 |
8 | # Visual Studio User Settings
9 | */.vs
10 | /.vs
11 | */TestResults
12 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 cryptic-wizard
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Description
2 | * A Github action to run SpecFlow tests and create a [SpecFlow+ LivingDoc](https://specflow.org/tools/living-doc/) artifact
3 | * SpecFlow projects must have a Package Reference to [SpecFlow.Plus.LivingDocPlugin](https://www.nuget.org/packages/SpecFlow.Plus.LivingDocPlugin/) in the [.csproj](https://github.com/cryptic-wizard/run-specflow-tests/blob/main/RunSpecflowTests/RunSpecflowTests.csproj)
4 | ```Shell
5 | dotnet add package SpecFlow.Plus.LivingDocPlugin
6 | ```
7 | ```xml
8 |
9 | ```
10 |
11 | ## Tests
12 | [](https://github.com/cryptic-wizard/run-specflow-tests/actions/workflows/dotnet6.yml)
13 |
14 | [](https://github.com/cryptic-wizard/run-specflow-tests/actions/workflows/dotnet7.yml)
15 |
16 | ## Usage
17 | #### Minimal:
18 | ```yaml
19 | steps:
20 | - uses: actions/checkout@v4
21 | - uses: actions/setup-dotnet@v4
22 | with:
23 | dotnet-version: '7.0.x'
24 | - uses: actions/cryptic-wizard/run-specflow-tests@v1.3.3
25 | with:
26 | test-assembly-path: MySpecflowProject/bin/Release/net7.0
27 | test-assembly-dll: MySpecflowProject.dll
28 | output-html: MyTestResults.html
29 | ```
30 |
31 | #### Test Multiple Operating Systems in the Same Workflow:
32 | ```yaml
33 | jobs:
34 | build:
35 | strategy:
36 | fail-fast: false
37 | matrix:
38 | os: [ubuntu-latest, macos-latest, windows-latest]
39 | runs-on: ${{ matrix.os }}
40 |
41 | steps:
42 | - uses: actions/checkout@v4
43 | - uses: actions/setup-dotnet@v4
44 | with:
45 | dotnet-version: '7.0.x'
46 | - uses: actions/cryptic-wizard/run-specflow-tests@v1.3.3
47 | with:
48 | test-assembly-path: MySpecflowProject/bin/Release/net7.0
49 | test-assembly-dll: MySpecflowProject.dll
50 | output-html: ${{ matrix.os }}.html
51 | ```
52 |
53 | #### Test Multiple Frameworks in Separate Workflows:
54 | * Target multiple frameworks in the [.csproj](https://github.com/cryptic-wizard/run-specflow-tests/blob/main/RunSpecflowTests/RunSpecflowTests.csproj)
55 | ```xml
56 | net6.0;net7.0
57 | ```
58 | * [dotnet6.yml](https://github.com/cryptic-wizard/run-specflow-tests/blob/main/.github/workflows/dotnet6.yml)
59 | * [dotnet7.yml](https://github.com/cryptic-wizard/run-specflow-tests/blob/main/.github/workflows/dotnet7.yml)
60 |
61 | #### Optional parameters:
62 | ```yaml
63 | - uses: actions/cryptic-wizard/run-specflow-tests@v1.3.3
64 | with:
65 | test-assembly-path: MySpecflowProject/bin/Debug/net7.0
66 | test-assembly-dll: MySpecflowProject.dll
67 | test-execution-json: TestExecution.json
68 | configuration: Debug
69 | output-html: MyTestResults.html
70 | build-verbosity: normal
71 | test-verbosity: minimal
72 | filter: TestCategory=CategoryA
73 | framework: net7.0
74 | no-build: true
75 | logger: trx
76 | logger-file-name: ../../MyTestResults.trx
77 | upload-artifact: false
78 | ```
79 | ## LivingDoc Output Example
80 | 
81 |
82 | 
83 |
84 |
85 | ## Features
86 | #### Recently Added
87 | * v1.3.3 - Add filter option
88 | ```yaml
89 | filter:
90 | ```
91 | * v1.3.2 - Patch for Github action exit code change - thanks again to awgeorge
92 | * v1.3.1 - test-execution-json now has default value
93 | ```yaml
94 | test-execution-json: 'TestExecution.json' by default
95 | ```
96 | * v1.3.0 - Autopublish artifacts - thanks [awgeorge](https://github.com/cryptic-wizard/run-specflow-tests/commit/60ce86858a5354c70db351767d7f96cd71b6c8b1)!
97 | ```yaml
98 | upload-artifact: true by default
99 | ```
100 | * v1.2.0 - Add configuration option
101 | ```yaml
102 | configuration:
103 | ```
104 | * v1.1.0 - Set working folder for test-assembly-dll and test-execution-json
105 | ```yaml
106 | test-assembly-path:
107 | ```
108 | * v1.1.0 - Allow other test loggers to be run in addition to SpecFlow
109 | ```yaml
110 | logger:
111 | logger-file-name:
112 | ```
113 |
114 | #### Planned Features
115 | Features planned when ['uses' keyword is implemented in composite actions](https://github.com/actions/runner/issues/646)
116 | * Checkout automatically
117 | * Setup dotnet automatically
118 | * Dotnet framework matrix testing
119 | ## Tools
120 | * [Visual Studio](https://visualstudio.microsoft.com/vs/)
121 | * [NUnit 3](https://nunit.org/)
122 | * [SpecFlow](https://specflow.org/tools/specflow/)
123 | * [SpecFlow+ LivingDoc](https://specflow.org/tools/living-doc/)
124 | ## License
125 | * [MIT License](https://github.com/cryptic-wizard/run-specflow-tests/blob/main/LICENSE.md)
126 |
--------------------------------------------------------------------------------
/RunSpecflowTests.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.1.32421.90
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RunSpecflowTests", "RunSpecflowTests\RunSpecflowTests.csproj", "{AE603549-94F5-4F84-AE14-5ABCFC58A8C9}"
7 | EndProject
8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C7AA17EA-DC20-456A-8035-F57942C911DD}"
9 | ProjectSection(SolutionItems) = preProject
10 | .gitignore = .gitignore
11 | action.yml = action.yml
12 | .github\workflows\dotnet6.yml = .github\workflows\dotnet6.yml
13 | .github\workflows\dotnet7.yml = .github\workflows\dotnet7.yml
14 | .github\workflows\dotnet6noartifacts.yml = .github\workflows\dotnet6noartifacts.yml
15 | LICENSE.md = LICENSE.md
16 | README.md = README.md
17 | EndProjectSection
18 | EndProject
19 | Global
20 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
21 | Debug|Any CPU = Debug|Any CPU
22 | Release|Any CPU = Release|Any CPU
23 | EndGlobalSection
24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
25 | {AE603549-94F5-4F84-AE14-5ABCFC58A8C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
26 | {AE603549-94F5-4F84-AE14-5ABCFC58A8C9}.Debug|Any CPU.Build.0 = Debug|Any CPU
27 | {AE603549-94F5-4F84-AE14-5ABCFC58A8C9}.Release|Any CPU.ActiveCfg = Release|Any CPU
28 | {AE603549-94F5-4F84-AE14-5ABCFC58A8C9}.Release|Any CPU.Build.0 = Release|Any CPU
29 | EndGlobalSection
30 | GlobalSection(SolutionProperties) = preSolution
31 | HideSolutionNode = FALSE
32 | EndGlobalSection
33 | GlobalSection(ExtensibilityGlobals) = postSolution
34 | SolutionGuid = {A450A81D-235B-4F0E-9117-AB06E3E9CDFB}
35 | EndGlobalSection
36 | EndGlobal
37 |
--------------------------------------------------------------------------------
/RunSpecflowTests/Features/Calculator.feature:
--------------------------------------------------------------------------------
1 | Feature: Calculator
2 | Simple calculator for adding **2** numbers
3 |
4 | [Calculator.feature](https://github.com/cryptic-wizard/run-specflow-tests/blob/main/RunSpecflowTests/Features/Calculator.feature)
5 | ***Further read***: **[Learn more about how to generate Living Documentation](https://docs.specflow.org/projects/specflow-livingdoc/en/latest/LivingDocGenerator/Generating-Documentation.html)**
6 |
7 | @mytag
8 | Scenario Outline: Add two numbers
9 | Given the first number is
10 | And the second number is
11 | When the two numbers are added
12 | Then the result should be
13 |
14 | Examples:
15 | | first | second | result |
16 | | 50 | 70 | 120 |
17 | | -5 | 7 | 2 |
18 | | 5 | -7 | -2 |
19 | | -5 | -7 | -12 |
20 |
21 | Scenario Outline: Subtract two numbers
22 | Given the first number is
23 | And the second number is
24 | When the two numbers are subtracted
25 | Then the result should be
26 |
27 | Examples:
28 | | first | second | result |
29 | | 50 | 70 | -20 |
30 | | -5 | 7 | -12 |
31 | | 5 | -7 | 12 |
32 | | -5 | -7 | 2 |
--------------------------------------------------------------------------------
/RunSpecflowTests/RunSpecflowTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0;net7.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/RunSpecflowTests/Steps/CalculatorStepDefinitions.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework.Legacy;
2 | using TechTalk.SpecFlow;
3 |
4 | namespace RunSpecflowSteps.Steps
5 | {
6 | [Binding]
7 | public sealed class CalculatorStepDefinitions
8 | {
9 | // For additional details on SpecFlow step definitions see https://go.specflow.org/doc-stepdef
10 |
11 | private readonly ScenarioContext _scenarioContext;
12 |
13 | public CalculatorStepDefinitions(ScenarioContext scenarioContext)
14 | {
15 | _scenarioContext = scenarioContext;
16 | }
17 |
18 | [Given("the first number is (.*)")]
19 | public void GivenTheFirstNumberIs(int number)
20 | {
21 | _scenarioContext.Add("firstNumber", number);
22 | }
23 |
24 | [Given("the second number is (.*)")]
25 | public void GivenTheSecondNumberIs(int number)
26 | {
27 | _scenarioContext.Add("secondNumber", number);
28 | }
29 |
30 | [When("the two numbers are added")]
31 | public void WhenTheTwoNumbersAreAdded()
32 | {
33 | int firstNumber = _scenarioContext.Get("firstNumber");
34 | int secondNumber = _scenarioContext.Get("secondNumber");
35 | ClassicAssert.IsNotNull(firstNumber);
36 | ClassicAssert.IsNotNull(secondNumber);
37 |
38 | int resultNumber = firstNumber + secondNumber;
39 | _scenarioContext.Add("resultNumber", resultNumber);
40 | }
41 |
42 | [When(@"the two numbers are subtracted")]
43 | public void WhenTheTwoNumbersAreSubtracted()
44 | {
45 | int firstNumber = _scenarioContext.Get("firstNumber");
46 | int secondNumber = _scenarioContext.Get("secondNumber");
47 | ClassicAssert.IsNotNull(firstNumber);
48 | ClassicAssert.IsNotNull(secondNumber);
49 |
50 | int resultNumber = firstNumber - secondNumber;
51 | _scenarioContext.Add("resultNumber", resultNumber);
52 | }
53 |
54 |
55 | [Then("the result should be (.*)")]
56 | public void ThenTheResultShouldBe(int result)
57 | {
58 | int resultNumber = _scenarioContext.Get("resultNumber");
59 | ClassicAssert.IsNotNull(resultNumber);
60 | ClassicAssert.AreEqual(result, resultNumber);
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/action.yml:
--------------------------------------------------------------------------------
1 | name: 'Run SpecFlow Tests'
2 | description: 'A Github Action to run SpecFlow tests and create a LivingDoc'
3 | author: 'cryptic-wizard'
4 | branding:
5 | icon: check-square
6 | color: green
7 |
8 | inputs:
9 | test-assembly-path:
10 | description: "Path of the working directory for build assemblies (example: MySpecflowProject/bin/Debug/net7.0)"
11 | required: false
12 | default: 'null'
13 | test-assembly-dll:
14 | description: "Relative path of (example: MySpecflowProject/bin/Debug/net7.0/MySpecflowProject.dll or MySpecflowProject.dll if using test-assembly-path)"
15 | required: true
16 | test-execution-json:
17 | description: "Relative path of (example: MySpecflowProject/bin/Debug/net7.0/TestExecution.json or TestExecution.json if using test-assembly-path)"
18 | required: false
19 | default: 'TestExecution.json'
20 | output-html:
21 | description: "Name of Specflow LivingDoc output file (must end with .html) (example: MyTestResults.html)"
22 | required: false
23 | default: 'LivingDoc.html'
24 | filter:
25 | description: "Run tests that match the given description (example: TestCategory=CategoryA or FullyQualifiedName~Calculator)"
26 | required: false
27 | default: 'null'
28 | framework:
29 | description: "Framework version of dotnet (example: net6.0, net7.0)"
30 | required: false
31 | default: 'null'
32 | configuration:
33 | description: "Build configuration (example: Debug)"
34 | required: false
35 | default: 'Release'
36 | build-verbosity:
37 | description: "Verbosity of the Dotnet App Build (default = minimal)"
38 | required: false
39 | default: 'minimal'
40 | test-verbosity:
41 | description: "Verbosity of the SpecFlow Test Execution (default = normal)"
42 | required: false
43 | default: 'normal'
44 | no-build:
45 | description: "Set to true to disable dotnet build and dotnet restore"
46 | required: false
47 | default: 'false'
48 | logger:
49 | description: "Dotnet test logger to run in addition to Specflow Test Logger (example: trx)"
50 | required: false
51 | default: 'null'
52 | logger-file-name:
53 | description: "Dotnet test log file name; required if logger is defined (example: MyTestResults.trx)"
54 | required: false
55 | default: 'null'
56 | upload-artifact:
57 | description: "Set to false to disable uploading artifact automatically"
58 | required: false
59 | default: 'true'
60 | runs:
61 | using: composite
62 | steps:
63 | - name: BuildDotnetApp
64 | run: |
65 | _args=()
66 | [ "${{ inputs.configuration }}" != 'null' ] && _args+=("-c" "${{ inputs.configuration }}")
67 | [ "${{ inputs.build-verbosity }}" != 'null' ] && _args+=("-v" "${{ inputs.build-verbosity }}")
68 | [ "${{ inputs.framework }}" != 'null' ] && _args+=("-f" "${{ inputs.framework }}")
69 |
70 | [ ${{ inputs.no-build }} == 'true' ] && echo 'Build Skipped' || dotnet build "${_args[@]}"
71 | shell: bash
72 | - name: RunSpecFlowTests
73 | run: |
74 | _args=()
75 | _logger_args=()
76 | [ "${{ inputs.configuration }}" != 'null' ] && _args+=("-c" "${{ inputs.configuration }}")
77 | [ "${{ inputs.build-verbosity }}" != 'null' ] && _args+=("-v" "${{ inputs.build-verbosity }}")
78 | [ "${{ inputs.filter }}" != 'null' ] && _args+=("--filter" "${{ inputs.filter }}")
79 | [ "${{ inputs.framework }}" != 'null' ] && _args+=("-f" "${{ inputs.framework }}")
80 | [ "${{ inputs.test-verbosity }}" != 'null' ] && _logger_args+=(";verbosity=${{ inputs.test-verbosity }}")
81 | [ "${{ inputs.logger-file-name }}" != 'null' ] && _logger_args+=(";LogFileName=${{ inputs.logger-file-name }}")
82 | [ "${{ inputs.logger }}" != 'null' ] && _args+=("-l" "${{ inputs.logger }}$(IFS=; echo "${_logger_args[@]}")")
83 |
84 | if ! dotnet test --no-build "${_args[@]}"; then
85 | echo "_EXIT=1" >> $GITHUB_ENV
86 | fi
87 | shell: bash
88 | continue-on-error: true
89 | - name: GenerateLivingSpec
90 | run: |
91 | [ "${{ inputs.test-assembly-path }}" != 'null' ] && _path="${{ inputs.test-assembly-path }}"
92 | _dll="${_path:+$_path/}${{ inputs.test-assembly-dll }}"
93 | _test="${_path:+$_path/}${{ inputs.test-execution-json }}"
94 |
95 | dotnet tool install --global SpecFlow.Plus.LivingDoc.CLI
96 | livingdoc test-assembly "$_dll" -t "$_test" -o "${{ inputs.output-html }}"
97 | shell: bash
98 | - name: 'Publish Specflow Test Results'
99 | if: ${{ inputs.upload-artifact == 'true' }}
100 | uses: actions/upload-artifact@v4
101 | with:
102 | name: 'Specflow Test Results'
103 | path: ${{ inputs.output-html }}
104 | - name: ReturnCode
105 | run: |
106 | exit "${_EXIT:-0}"
107 | shell: bash
108 |
--------------------------------------------------------------------------------