We're trying to implement global hooks on our specflow tests and are not entirely sure how [BeforeScenario] and [AfterScenario] attributed methods work.
The way I've seen it done, those attributes are always defined in a class containing specific steps used in a few scenarios.
Can they go somewhere so they apply to all scenarios? Or does attributing the methods with [BeforeScenario] and [AfterScenario] cause them to be run for all scenarios, regardless of where they're actually placed?
Hmm... From what I knew and according to the documentation these hooks are always global, i.e. from http://www.specflow.org/documentation/hooks/
Hooks
The hooks (event bindings) can be used to perform additional automation logic on specific events, like before the execution of a scenario.
The hooks are global but can be restricted to run only for features or scenarios with a specific tag (see below). The execution order of hooks for the same event is undefined.
In fact by producing a small demo project with the following
[Binding]
public class Unrelated
{
[BeforeScenario]
public void WillBeCalledIfGlobal()
{
Console.WriteLine("I'm global");
}
}
[Binding]
public class JustTheTest
{
[Given("nothing")]
public void GivenNothing()
{
// Don't do anything
}
}
Then the test specification of
As a developer
In order to understand how BeforeSpecifcation works
I want to know what the following does
Scenario: See if BeforeSpecifcation hook gets called
Given nothing
The get the output
I'm global
Given nothing
-> done: JustTheTest.GivenNothing() (0.0s)
So it really does look as if the documentation is correct, and you should use tagging to control if the BeforeScenario \ AfterScenario are run before or after your scenario.
There is also a good example of how tagging works here -> Feature-scoped step definitions with SpecFlow?
Yes, you can create global BeforeScenario and AfterScenario methods, but in practice I find that this is not desirable, as usually the same before and after steps do not apply to all steps in a test project.
Instead I create a base class for my step definitions, which would have the BeforeScenario and AfterScenarios methods I'd like applied to all of my scenarios e.g.
public class BaseStepDefinitions
{
[BeforeScenario]
public void BeforeScenario()
{
// BeforeScenario code
}
[AfterScenario]
public void AfterScenario()
{
// AfterScenario code
}
}
Note that I have not used the Binding attribute on this class. If you do include it then the BeforeScenario and AfterScenario steps would be global.
I then derive my step definion classes from this base step definition class, so that they will have the Before and After scenario methods e.g.
[Binding]
public class SpecFlowFeature1Steps : BaseStepDefinitions
{
[Given(#"I have entered (.*) into the calculator")]
public void GivenIHaveEnteredIntoTheCalculator(int inputValue)
{
ScenarioContext.Current.Pending();
}
[When(#"I press add")]
public void WhenIPressAdd()
{
ScenarioContext.Current.Pending();
}
[Then(#"the result should be (.*) on the screen")]
public void ThenTheResultShouldBeOnTheScreen(int expectedResult)
{
ScenarioContext.Current.Pending();
}
}
Whilst this approach is not global, by making all StepDefinitions derive from a BaseStepDefinition class we achieve the same outcome.
It also gives more control i.e. if you don't want the BeforeScenario or AfterScenario binding then don't derive from the base steps.
Sorry this doesn't work. As soon as you start using multiple Binding classes you end up with multiple calls. For example if I extend the example above to split the bindings into three classes,
[Binding]
public class SpecFlowFeature1Steps : BaseStepDefinitions
{
[Given(#"I have entered (.*) into the calculator")]
public void GivenIHaveEnteredIntoTheCalculator(int inputValue)
{
//ScenarioContext.Current.Pending();
}
}
[Binding]
public class SpecFlowFeature2Steps : BaseStepDefinitions
{
[When(#"I press add")]
public void WhenIPressAdd()
{
//ScenarioContext.Current.Pending();
}
}
[Binding]
public class SpecFlowFeature3Steps : BaseStepDefinitions
{
[Then(#"the result should be (.*) on the screen")]
public void ThenTheResultShouldBeOnTheScreen(int expectedResult)
{
//ScenarioContext.Current.Pending();
}
}
public class BaseStepDefinitions
{
[BeforeScenario]
public void BeforeScenario()
{
// BeforeScenario code
Console.WriteLine("Before. [Called from "+ this.GetType().Name+"]");
}
[AfterScenario]
public void AfterScenario()
{
// AfterScenario code
Console.WriteLine("After. [Called from " + this.GetType().Name + "]");
}
}
Then when I run it, the output is
Before. [Called from SpecFlowFeature1Steps]
Before. [Called from SpecFlowFeature2Steps]
Before. [Called from SpecFlowFeature3Steps]
Given I have entered 50 into the calculator
-> done: SpecFlowFeature1Steps.GivenIHaveEnteredIntoTheCalculator(50) (0.0s)
And I have entered 70 into the calculator
-> done: SpecFlowFeature1Steps.GivenIHaveEnteredIntoTheCalculator(70) (0.0s)
When I press add
-> done: SpecFlowFeature2Steps.WhenIPressAdd() (0.0s)
Then the result should be 120 on the screen
-> done: SpecFlowFeature3Steps.ThenTheResultShouldBeOnTheScreen(120) (0.0s)
After. [Called from SpecFlowFeature1Steps]
After. [Called from SpecFlowFeature2Steps]
After. [Called from SpecFlowFeature3Steps]
What you can do, in order to control the 'BeforeScenario' and 'AfterScenario' is use tags. This gives you the control of which Scenario's should run which before and after block. Your scenario would look like this:
#GoogleChrome
Scenario: Clicking on a button
Given the user is on some page
When the user clicks a button
Then something should happen
Here you could let the 'BeforeScenario' start a browser session in Google Chrome for you, and implement similar tags for different browsers. Your 'BeforeScenario' would look like this:
[Binding]
class Browser
{
[BeforeScenario("GoogleChrome")]
public static void BeforeChromeScenario()
{
// Start Browser session and do stuff
}
[AfterScenario("GoogleChrome")]
public static void AfterChromeScenario()
{
// Close the scenario properly
}
I think using tags is a nice way of keeping your scenario's clean and give you the extra functionality to let you control what each scenario should do.
Related
I want to execute a block of code that changes based on a pass or a fail. Basically looking to set the results from a test in our test case tracking software. I created my own test rules, shown below, but no matter if the test passes or fails it always just calls succeeded.
public class TestRules extends TestWatcher {
#Override
public void succeeded(Description description){
log.error("This should only be called when passing");
}
#Override
public void failed(Throwable e, Description description) {
log.error("This Should only be called when Failing");
}
}
I set the rule in the test as follows
#Rule
public TestRules testRules = new TestRules()
I am hoping I am just missing something stupid and simple.
Is there a way to retrieve if a Specflow scenario step starts with And or But instead of the Given/When/Then ? I want to write the steps into a text.
Eg:
Given this is a step
And this is another one
When I do something
Then something happen
But something else dont
Is the And/But stored anywhere that I can retrieve?
Thanks!
It could be, that it this information is available in the StepInfo (https://github.com/techtalk/SpecFlow/blob/master/TechTalk.SpecFlow/StepInfo.cs).
[Binding]
public class Binding
{
private ScenarioContext _scenarioContext;
public Binding(ScenarioContext scenarioContext)
{
_scenarioContext = scenarioContext;
}
[AfterStep()]
public void AfterStepHook()
{
var stepText = _scenarioContext.ScenarioStepContext.StepInfo.Text;
}
}
Code written without compiling/running.
So I have a few tests where i've reused steps from within steps.
But i'm now having a nightmare on the maintenance front, in that I cant easily navigate between the steps.
Here's an example:
[Given(#"I have an order")]
public void GivenIHaveAnOrder()
{
Given("an open store");
Given("I am an existing customer");
Given("I am on homepage");
When("I search for a component");
When("I add the component to my basket");
}
How do I navigate to one of those internal steps?
If I wanted to navigate to the "When("I search for a component");" step I cant.
If I were on the feature file I could simply right click the step and "go to definition" but I cant do that here. Does anyone have a solution?
I assume that you are calling the steps with the Given/When- functions, because they are in a different binding class. Am I right?
There is a better way of doing it, than using this functions.
Did you had a look at the driver concept and context injection?
Have a look here: http://www.specflow.org/documentation/Context-Injection/
Simply extract your logic of your steps to a driver class and get an instance from it in the different step classes:
class Driver
{
public void AnOpenStore()
{
...
}
}
[Binding]
public class StepClass1
{
private Driver _driver;
public StepClass1(Driver driver)
{
_driver = driver;
}
[Given(#"I have an order")]
public void IHaveAnOrder()
{
_driver.AnOpenStore();
}
}
[Binding]
public class StepClass2
{
private Driver _driver;
public StepClass2(Driver driver)
{
_driver = driver;
}
[Given(#"an open store")]
public void AnOpenStore()
{
_driver.AnOpenStore();
}
}
When you arrange your step implementations like that, the reusing of other steps is much more easier.
I've been having a bit of trouble with this.
Andreas Öhlund answered a question on it here, but I've been unable to get it to work using the advice he gave.
Here's my setup:
public abstract class CommandHandler<T> : IHandleMessages<T>, IDomainReadRepository where T : Command
{
public IDomainRepository DomainRepository { get; set; }
protected abstract void OnProcess(T command);
public TAggregate GetById<TAggregate>(Guid id) where TAggregate : IEventProvider, new()
{
return DomainRepository.GetById<TAggregate>(id);
}
public void Handle(T message)
{
OnProcess(message);
// Domain repository will save.
}
}
The idea is specific command handlers override the OnProcess method and do their thing, then the DomainRepository will save everything.
Here is how I've registered the components:
public class EndpointConfig : IConfigureThisEndpoint, AsA_Server, IWantCustomInitialization
{
public void Init()
{
Configure.With().DefiningCommandsAs(c => c.Namespace != null && c.Namespace.EndsWith("Commands"));
Configure.Instance.DefaultBuilder().Configurer.ConfigureComponent<DomainRepository>(DependencyLifecycle.InstancePerCall);
Configure.Instance.DefaultBuilder().Configurer.ConfigureComponent<EventStore.Sql.EventStore>(DependencyLifecycle.InstancePerCall);
Configure.Instance.DefaultBuilder().Configurer.ConfigureComponent<MongoDbObjectSecurityDescriptorRepository>(DependencyLifecycle.InstancePerCall);
Configure.Instance.DefaultBuilder().Configurer.ConfigureComponent<LocalTenantConfig>(DependencyLifecycle.InstancePerCall);
}
}
Those are all the objects down the chain that are used by the DomainRepository; however, when I receive a command, the DomainRepository is null. If I comment out the lines to register the objects that DomainRepository needs, I'll actually get an error saying it failed to create it (Autofac DependencyResolutionException).
It should be noted that all the other objects use constructor injection (they're taken from a previously existing project). I tried changing them to use public property injection, but it didn't make any difference.
It would be much appreciated if somebody could point out what I'm doing wrong here!
Move the code in your init method into a different class which implements INeedInitialization. In there, use Configure.Instance instead of Configure.With() and also instead of Configure.Instance.DefaultBuilder().
I'm not sure if this is possible, but I though I'd ask the question anyway.
I have a scenario where I have a number of different tasks which send emails during processing.
The sending of emails is done via a custom class
public interface IEmailProvider
{
void SendEmail(some params);
}
public class EmailProvider : IEmailProvider
{
private readonly IEmailConfig _config;
public EmailProvider(IEmailConfig config)
{
_emailConfig = emailConfig;
}
public void SendEmail(some params)
{
// send the email using the params
}
}
I have some tasks which use the email provider, each providing their own implementation of IEmailConfig.
public class Task1 : ICommand
{
public Task1(IEmailProvider emailProvider)
{}
}
public class Task2 : ICommand
{
public Task2(IEmailProvider emailProvider)
{}
}
This is a basic example of my set up
public class TestInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
// Default email provider set up
container.Register(Component.For<IEmailProvider>().ImplementedBy<EmailProvider>()
.Named("DefaultEmailProvider")
.LifeStyle.Transient);
// Task 1 email config set up
container.Register(Component.For<IEmailConfig>().ImplementedBy<Task1EmailConfig>()
.Named("Task1EmailConfig"));
// Task 2 email config set up
container.Register(Component.For<IEmailConfig>().ImplementedBy<Task2EmailConfig>()
.Named("Task2EmailConfig"));
// Task 1 set up
container.Register(Component.For<ICommand>().ImplementedBy<Task1>()
.Named("Task1Command"));
// Task 2 set up
container.Register(Component.For<ICommand>().ImplementedBy<Task2>()
.Named("Task2Command"));
}
}
Is there a way I can make a decision, as each ICommand implementation is being resolved, as to which implementation of IEmailConfig to pass into the constructor of the EmailProvider class?
At the moment I register an EmailProvider instance for each task using the ServiceOverride functionality. This means that for each task that need to send emails, I have to almost duplicate the set up of the email provider and it's required config. I end up with something list this...
Component.For<IEmailConfig>()
.ImplementedBy<Task1EmailConfig>()
.Named("Task1EmailConfig"));
Component.For<IEmaiProvider>()
.ImplementedBy<EmailProvider>)
.Named("Task1EmailProvider")
.DependsOn(ServiceOverride.ForKey("config").Eq("Task1Config"));
Component.For<ICommand>()
.ImplementedBy<Task1>()
.DependsOn(ServiceOverride.ForKey("emailProvider").Eq("Task1EmailProvider")));
This will all be duplicated for each task.
The IEmailProvider implementation is always the same, it's only the IEmailConfig passed in that changes for each different task. I can't help thinking there must be a neater solution to the one I've got so far.
I think a couple of handler selectors would work for what you want. One for IEmailProvider and one for ICommand.
The IEmailProvider one could check the name of the IEmailProvider being activated (like "Task1EmailProvider") and strip off the "Provider" and add on "Config" -- which would give you the key "Task1EmailConfig" which could be used to resolve the particular IEmailConfig object.
Likewise, do the same thing for ICommand's. It would rely on you naming your IEmailConfig's consistently, but it would eliminate all of that hand-wiring you're doing now.