CucumberSwift icon indicating copy to clipboard operation
CucumberSwift copied to clipboard

use Feature and Scenario for better test results

Open bitsmakerde opened this issue 2 years ago • 3 comments

@Tyler-Keith-Thompson I try make a better test case struct in my project, but I'm not sure which is the way to get this.

Here my first idea:

I create one StepImplementation and import here my Features:

import CucumberSwift

extension Cucumber: StepImplementation {
	public var bundle: Bundle {
		class FindMe {}
		return Bundle(for: FindMe.self)
	}

	public func setupSteps() {
		SaveImageLocallyTests().steps()
		DeleteImageLocallyTests().steps()
	}
}

Inside every feature I have something like this:

import CucumberSwift
import CucumberSwiftExpressions

class DeleteImageLocallyTests: XCTestCase {
	func steps() {
		Feature("Delete an image") {
			Scenario("Delete an image locally") {
				Given("the user has a local stored image" as CucumberExpression) { _, _ in
				}

				When("he delete the image" as CucumberExpression) { _, _ in
				}

				Then("the local store should be empty" as CucumberExpression) { _, _ in
				}
			}
		}
	}
}

For me is to work with feature and scenario very useful to have a good strutted code. but if I look to the test results in Xcode I get a different list, which not use my feature and scenario. Is there a best practice to have all in a good struct?

image

bitsmakerde avatar Dec 27 '22 11:12 bitsmakerde

I will try and play with some options to give you a better answer, but for right this second you seem to be using a mixture of the DSL and feature files. I really recommend only using one. Your current code isn't quite supported as is.

If you're going to use the DSL, you don't need to use the Given/When/Then methods that take a string or regex, for example

Feature("Delete an image") {
    Scenario("Delete an image locally") {
        Given(the: userHasALocallyStoredImage())
        When(the: imageIsDeleted())
        Then(the: localStoreShouldBeEmpty())
    }
}

func userHasALocallyStoredImage() { XCTFail("Implement the step") }
func imageIsDeleted() { XCTFail("Implement the step") }
func localStoreShouldBeEmpty { XCTFail("Implement the step") }

If you're going with .feature files, I don't recommend wrapping your steps in the Feature/Scenario DSL. So instead do:

func steps() {
    Given("the user has a local stored image" as CucumberExpression) { _, _ in }
    When("he delete the image" as CucumberExpression) { _, _ in }
    Then("the local store should be empty" as CucumberExpression) { _, _ in }
}

It's possible that some of what you're seeing with all those duplicate entries is really a byproduct of mixing and matching the 2 methods of executing Gherkin.

That said, I am sadly very limited here. Apple doesn't really give access to this in a sane way. The only way CucumberSwift is able to show up in that navigator at all is to use the Objective-C runtime to dynamically create classes. The | character was used to delineate between features and scenarios in those test case names. I'll leave this issue open so I can explore a bit and see if we can do better.

Tyler-Keith-Thompson avatar Dec 28 '22 09:12 Tyler-Keith-Thompson

@Tyler-Keith-Thompson thank you for this nice answer.

But both ways look for me not so "sexy" at the moment.

Why I think so. I like to see a one to one relation for the .feature to the source code. But in both ways something is missing like the Feature / Scenario or the Given/When/Then description text.

One other point I find out is, that I can't start a Scenario separate.

What do you think if a Scenario is warp inside a func test_... so Xcode can find this a test run it and can show it automatic in the navigator. For this case for me its fine only to see the scenario is failed and being inspect the detail I see there its fails.

I try the first way, but for it not really work. CucumberSwift says's alway not implementation for my feature.

Will it be a problem if I stay by my code?

bitsmakerde avatar Dec 28 '22 14:12 bitsmakerde

I comment the duplicate code out. But it not looking nice.

  // swiftlint:disable todo
  // TODO: - Feature("Delete an image")
  // MARK: - Scenario("Delete an image locally")
        
        Given("the user has selected an image to save" as CucumberExpression) { _, _ in
            ...
        }
        
        When("the image is saved to the selected location on the device's storage" as CucumberExpression) { _, _ in
            ...
        }
        
        Then("the image becomes persistent on the phone" as CucumberExpression) { _, _ in
           ...
        }

This looks like this in Xcode

image

bitsmakerde avatar Dec 28 '22 14:12 bitsmakerde