BeforeScenario executed before derived class was created

798 views
Skip to first unread message

Vajda

unread,
Mar 17, 2011, 2:17:39 PM3/17/11
to SpecFlow
I said almost everything in subject, here is my code:

// base class
public abstract class StepDefinition
{
public abstract IOfficeAppDriver OfficeAppDriver();
[BeforeScenario]
public void BeforeScenario()
{
OfficeAppDriver().Start();
}
}

// derived class
[Binding]
public class ExcelStepDefinition : StepDefinition
{
IExcelDriver excelDriver;
string cell;

public ExcelStepDefinition()
{
excelDriver = new ExcelDriver(new
ReportFactoryOfficeAddInDriver(new Excel2007Repository()));
}

public override IOfficeAppDriver OfficeAppDriver()
{
return excelDriver;
}

When I try to execute test I get "No public constructors for type
ABZ.OfficeAddInTestLogic.StepDefinition"
It's like specflow tries to make instance of abstract class. When I
make public constructor it fails on making instance of abstract class.
Shouldn't BefforeScenario execute after derived constructor?
How to solve this?
My base class is in "ABZ.OfficeAddInTestLogic" namespace, and my
derived class is in "ABZ.ExcelTest" namespace.
I also tried another aproach to this problem which failed too, you can
look it here:
http://stackoverflow.com/questions/5326210/specflow-step-definition-inheritance

Regards,

Vajda

Vajda

unread,
Mar 18, 2011, 9:09:35 AM3/18/11
to SpecFlow
I found where problem is, but it seems it's specflow's bug.
We have one binding class which is derived from class with NO
[Binding] attribute, but with some methods that have [When...]
attributes.
Specflow gathers information's of all methods from our [Binding] class
and it's ancestor classes. Since it finds that some ancestor class has
some binding attributes it assumes this class should be instanced to.
And it makes one instance of derived class with [Binding] attribute,
and makes one instance of base class which has some attributes (like
[When..], [Given..]) but NO [Binding] attribut. Which is wrong.

Regards,

Vajda

Jonas Bandi

unread,
Mar 18, 2011, 5:34:16 PM3/18/11
to spec...@googlegroups.com
I think there is a misunderstanding here.

I think it does not make sense to use inheritance the way you propose it.
SpecFlow works quite different compared to traditional xUnit Test frameworks.
In SpecFlow step-definitions are global. Step definitions do not have
to reside in a base class to be usable from a subclass. Step
definitions are not comparabe to methods in test fixtures from xUnit
frameworks.

Generally all classes that are decorated with the [Binding] attribute
are scanned by SpecFlow to discover step definitions.
All the step definitions that are found are availabe at runtime when
SpecFlow parses and executes features.
For SpecFlow to find a matching step definition it is not relevant in
which class the step definitiond is definied.

However when SpecFlow has found a matching step definition, it needs
to be able to instantiate the class on which it is defined. Therefore
classes that contain step definitions must not be abstract.
The instance is primarily used to pass state between related step
definitions (however there are other possibilities to pass state).

The same is true for hooks (Before .../ After ...): They are global,
at runtime it does not matter on which class they are defined.

The above is the general concept.
Things get a bit more complicated, when we start considering scoped steps:
Step definitions can be scoped to tags and scenarios, hooks can be
scoped to tags.

Examples:
https://github.com/techtalk/SpecFlow/blob/master/Tests/FeatureTests/ScopedSteps/ScopedStepsBindings.cs
https://github.com/techtalk/SpecFlow-Examples/blob/master/ASP.NET-MVC/BookShop/BookShop.AcceptanceTests.Selenium/Support/SeleniumSupport.cs

Read more here:
http://groups.google.com/group/specflow/browse_frm/thread/080c531cb17c86e0/5350665da2544871?#5350665da2544871


Read more on the Cucumber wiki.
About global steps:
https://github.com/aslakhellesoy/cucumber/wiki/Feature-Coupled-Steps-%28Antipattern%29
Step organisation:
https://github.com/aslakhellesoy/cucumber/wiki/Step-Organisation

--
mail: jonas...@gmail.com
web: www.jonasbandi.net
blog: blog.jonasbandi.net
twitter: twitter.com/jbandi

pedjak

unread,
Mar 19, 2011, 6:58:57 PM3/19/11
to SpecFlow
> I think it does not make sense to use inheritance the way you propose it.
> SpecFlow works quite different compared to traditional xUnit Test frameworks.
> In SpecFlow step-definitions are global. Step definitions do not have
> to reside in a base class to be usable from a subclass. Step
> definitions are not comparabe to methods in test fixtures from xUnit
> frameworks.

Hi Jonas,

Why would it not make sense? The problem here is that SpecFlow tries
to instantiate a class that is not even decorated with the Binding
attribute, and it should not. SpecFlow should create only instance of
class having Binding attribute, which happens to extend a class
containing some steps due to a good reason - reusing steps and code
for testing different applications/modules.

Vladimir and I are using SpecFlow to test an Office plugins that is
available both in Excel and Word. Since the plugin is not a standalone
application, we have identified some steps and other code parts that
are the same (and code behind them too) and can be reused both in Word
and Excel context. Thus, we have had an idea to specify these steps in
an abstract class (not decorated with Binding attribute) and extend it
(and decorating with Binding attribute) with additional steps and code
needed for testing within Word or Excel.

It should not be hard to support such a scenario: when a step method
is found, it should be checked if the class defining the method is
defined has Binding attribute, and if not - remember that the class
with Binding attribute should be instantiated instead.

Best,

Predrag
>
> Generally all classes that are decorated with the [Binding] attribute
> are scanned by SpecFlow to discover step definitions.
> All the step definitions that are found are availabe at runtime when
> SpecFlow parses and executes features.
> For SpecFlow to find a matching step definition it is not relevant in
> which class the step definitiond is definied.
>
> However when SpecFlow has found a matching step definition, it needs
> to be able to instantiate the class on which it is defined. Therefore
> classes that contain step definitions must not be abstract.
> The instance is primarily used to pass state between related step
> definitions (however there are other possibilities to pass state).
>
> The same is true for hooks (Before .../ After ...): They are global,
> at runtime it does not matter on which class they are defined.
>
> The above is the general concept.
> Things get a bit more complicated, when we start considering scoped steps:
> Step definitions can be scoped to tags and scenarios, hooks can be
> scoped to tags.
>
> Examples:https://github.com/techtalk/SpecFlow/blob/master/Tests/FeatureTests/S...https://github.com/techtalk/SpecFlow-Examples/blob/master/ASP.NET-MVC...
>
> Read more here:http://groups.google.com/group/specflow/browse_frm/thread/080c531cb17...
>
> Read more on the Cucumber wiki.
> About global steps:https://github.com/aslakhellesoy/cucumber/wiki/Feature-Coupled-Steps-...
> Step organisation:https://github.com/aslakhellesoy/cucumber/wiki/Step-Organisation
>
>
>
>
>
>
>
>
>
> On Fri, Mar 18, 2011 at 2:09 PM, Vajda <vladava...@gmail.com> wrote:
> > I found where problem is, but it seems it's specflow's bug.
> > We have one binding class which is derived from class with NO
> > [Binding] attribute, but with some methods that have [When...]
> > attributes.
> > Specflow gathers information's of all methods from our [Binding] class
> > and it's ancestor classes. Since it finds that some ancestor class has
> > some binding attributes it assumes this class should be instanced to.
> > And it makes one instance of derived class with [Binding] attribute,
> > and makes one instance of base class which has some attributes (like
> > [When..], [Given..]) but NO [Binding] attribut. Which is wrong.
>
> > Regards,
>
> > Vajda
>
> --
> mail: jonas.ba...@gmail.com

Jonas Bandi

unread,
Mar 20, 2011, 8:57:38 AM3/20/11
to spec...@googlegroups.com
You have a point, but that is not how SpecFlow works. However your
usage scenario is not new, many users of SpecFlow are reusing
functionality with SpecFlow and SpecFlow provides mechanisms for this
(see below).

If SpecFlow wants to execute a step definition at runtime, it needs to
instantiate an object that contains this step definition.
Currently SpecFlow tries to instantiate the class that defines the
step definition.
Currently SpecFlow has no way to find out which subclass it should
instantiate when running a scenario.
There is no relation beween scenarios and step definitions or the
classes that implement step definitions. Step definitions are global
and not feature or scenario coupled.

So as a rule: Step definitions must be declared in classes that will
get instantiated at runtime.

Steps can be shared for both of you plugins without using inheritance.
For instance you can implement three classes:

SharedSteps.cs
ExcelSteps.cs
WordSteps.cs

SpecFlow will discover the steps at runtime. For the Excel scenarios
it will use the ExcelSteps and the SharedSteps for Word scenarios it
will use WordSteps and SharedSteps. But it will have all steps always
available.

If you need the same steps (same regexp binding) but with different
meaning depending on the context you are using them then there are two
different solutions:
- If you have two independent projects for Word and Excel, you could
use three different assemblies that contain the steps. In the
Word-solution you would only reference the assemblies containting the
SharedSteps and the WordSteps.

- You can use scoped steps:
https://github.com/techtalk/SpecFlow/blob/master/Tests/FeatureTests/ScopedSteps/ScopedStepsBindings.cs
As the above example shows you can scope a single step definition or a
whole class containing step definitions to tags, scenarios or
features.
At runtime SpecFlow will then choose the step definition that matches
best to your scenario.

As seen in the example above this is accomplished by using tags
(@excel, @word) on your scenarios.
Then use for example step bindings like this:
[StepScope(Tag = "excel")]
[StepScope(Feature = "Excel plugin feature bla bla")]
[StepScope(Scenario = "Word is automatically completing sentences")]
[StepScope(Tag = "excle", Scenario = "Excel plugin feature bla bla")]


If you need shared functionality, you can place it in a abstract
base-class. But this base-class cannot contain step definition itself.
You can also inject common used instances as context into step classes
with dependency injection:
https://github.com/techtalk/SpecFlow/blob/master/Tests/FeatureTests/ContextInjection/FeatureWithASingleContextSteps.cs

--
mail: jonas...@gmail.com

Predrag Knežević

unread,
Mar 21, 2011, 5:17:57 AM3/21/11
to spec...@googlegroups.com
> If SpecFlow wants to execute a step definition at runtime, it needs to
> instantiate an object that contains this step definition.
> Currently SpecFlow tries to instantiate the class that defines the
> step definition.
> Currently SpecFlow has no way to find out which subclass it should
> instantiate when running a scenario.

This is exactly what we discovered as well by looking at the code in
BindingRegistry and MethodBinding classes. However, thanks to the good
code design, this could changed easily: in
BindingRegistry.BuildBindingsFromType(Type type) one can check if the
method declaring type is the same as the type discovered via Binding
attribute, and if not to instantiate the discovered type in
MethodBinding.CreateActionDelegate() instead. What do you think about
this? If you do not see any problem with this, we would be keen to
contribute the patch, if you agree - of course.

> There is no relation beween scenarios and step definitions or the
> classes that implement step definitions. Step definitions are global
> and not feature or scenario coupled.

This is fine and understandable, but if developer introduces some
orthogonal coupling (i.e. steps spread in a base abstract class and
inherited class), SpecFlow could detect such a situation (see above)
and instantiate at the runtime only classes that are decorated with
Binding attribute (in our case - this is only the inherited class).
Otherwise, what is then the purpose of the Binding attribute, if
SpecFlow tries to instantiate classes containing some SpecFlow steps,
but are not decorated with the Binding attribute?

> If you need the same steps (same regexp binding) but with different
> meaning depending on the context you are using them then there are two
> different solutions:
> - If you have two independent projects for Word and Excel, you could
> use three different assemblies that contain the steps. In the
> Word-solution you would only reference the assemblies containting the
> SharedSteps and the WordSteps.

This is the approach we tend to use, but our shared and word/excel
steps need to use the same instance of Word/Excel driver class. Here
is the class hierarchy:
interface IOfficeAppDriver {
}
interface IExcelDriver: IOfficeAppDriver {
}

Now, the shared steps need a reference to an instance of
IOfficeAppDriver, whereas Excel steps need reference to an instance of
IExcelDriver. Furthermore, we have different implementations of
IExcelDriver, depending on the Excel version itself, and we wanted to
inject of create it in the constructor of Excel step class. Hence, we
needed to define shared step class as abstract and to inherit
Excel/Word step class out of it.

Speaking about dependency injection, could you please clarify what is
going on in the following situation:

[Binding]
class StepDefinition1 {
public StepDefinition1(A a) {
}
}

[Binding]
class StepDefinition2 {
public StepDefinition2(A a) {
}
}

Do both step definition classes get a shared instance of type A, or
each of them gets its own instance?

Best,

Predrag

Gáspár Nagy

unread,
Mar 21, 2011, 4:38:56 PM3/21/11
to SpecFlow
I agree with you both :-) actually as a .net developer it feels quite
natural that the steps - along with the attributes are inherited,
though as Jonas pointed out, this is not the most common way of
sharing the steps.

I have one more aspect to throw in: the binding attribute was invented
to support the tools working with the bindings. particularly, for the
VS2010 integration, it is a big performance boost, that we only have
to investigate the classes with the binding attribute. this means that
the steps from the abstract class won't be processed. thretfore I
think, if we want to allow the binding inheritance, the rule sholud be
that you add the binding attribute also to the base class, but keep it
abstract. the logic sholud consider the abstract flag of the binding
classes too, and handle it accordingly (ignore for runtime, process un
VS2010 integration).

Jonas Bandi

unread,
Mar 21, 2011, 5:54:09 PM3/21/11
to spec...@googlegroups.com
Contributing a patch: Yes please! We would be happy to apply your your
improvements.
I am still wondering how you would solve the problem when there are
several subclasses for a baseclass at runtime ... but it would be an
improvement in any case.

Dependency injection:
This is currently solved with a simple Dictionary<Type, object> that
is instantiated per scenario.
So, yes: In your case both step definition classes get the same
instance injected during the same scenario.

Thanks for your help.
jonas


2011/3/21 Predrag Knežević <ped...@gmail.com>:

--

Vajda

unread,
Mar 23, 2011, 10:49:56 AM3/23/11
to SpecFlow
Is there some special plugin to install to be able to Build specflow
source on my machine?
I have troubles with reading Vs2010Integration project.
> mail: jonas.ba...@gmail.com

Jonas Bandi

unread,
Mar 23, 2011, 10:52:41 AM3/23/11
to spec...@googlegroups.com
https://github.com/techtalk/SpecFlow/wiki/Building-SpecFlow

Did you take this into account? (its not much) ... also if you have
any tips, please update this wiki ...

--
mail: jonas...@gmail.com

Vajda

unread,
Mar 23, 2011, 11:58:26 AM3/23/11
to SpecFlow
Thanks, now I could read all project and start build,.
But have some other problem concerning wix
Just to note, I had to place platform to x86 to al TechTalk.Specflow*
projects.
Here is error:

Error 8 The file with id 'extension.vsixmanifest_VS2010' and name
'adwewb2m.vsi|extension.vsixmanifest' could not be found with source
path: 'D:\Projects\VS2008\techtalk-SpecFlow-8b2a5bf\IdeIntegration
\Vs2010Integration\bin\x86\Debug\\extension.vsixmanifest'. D:\Projects
\VS2008\techtalk-SpecFlow-8b2a5bf\Installer\SpecFlowInstaller
\VS2010.wxs 19 1 SpecFlowInstaller

the name and id in .wxs file looks normal:

<File Id="extension.vsixmanifest_VS2010"
Name="extension.vsixmanifest" Source="$
(var.TechTalk.SpecFlow.Vs2010Integration.TargetDir)
\extension.vsixmanifest" />
Message has been deleted

Jonas Bandi

unread,
Mar 23, 2011, 4:52:32 PM3/23/11
to spec...@googlegroups.com
Great!
Please update the wiki if you find something that you find useful for
starting to commit to SpecFlow.

On Wed, Mar 23, 2011 at 6:15 PM, Vajda <vlada...@gmail.com> wrote:
> I solved it, I had Wix 3.6 on my machine, when I replaced it with wix
> 3.5 it built like magic. :)
>
> regards,
>
> Vajda

--
mail: jonas...@gmail.com

Vajda

unread,
Mar 24, 2011, 2:39:20 PM3/24/11
to SpecFlow
I sent pull request with bug fixture.
And provided feature file with test in RuntimeTest to test this
problem.

Please look at it.
I'm eager to hear your opinion.


regards,

Vajda

Alan Christensen

unread,
Mar 24, 2011, 6:05:45 PM3/24/11
to SpecFlow
I just encountered this same problem.

I was using global event definitions with a tag to differentiate
between whether the transaction scope step definitions were run or
not.
However, I was not comfortable with the scenarios "knowing" about
these details. Really they are just about implementing the "When" (and
cleaning up afterwards).

Ideally I would be able to specify BeforeScenario and AfterScenario
hooks for individual step definition classes rather than globally.
I would also like to be able to re-use an aspect (such as transaction
scope as in Vajda's example) in multiple step definitions. Obviously
subclassing is one way to do it.

Any thoughts on if this is possible in SpecFlow or is there a better
approach?

Jonas Bandi

unread,
Mar 24, 2011, 6:59:05 PM3/24/11
to spec...@googlegroups.com
Thanks a lot for your quick contribution. We will have a look. Please
give us some time, I think it will not be able to match your pace :-)

--

Vajda

unread,
Mar 25, 2011, 9:59:23 AM3/25/11
to SpecFlow
Ok, just write here something when you take a look.
It was my pleasure. :-)

On Mar 24, 11:59 pm, Jonas Bandi <jonas.ba...@gmail.com> wrote:
> Thanks a lot for your quick contribution. We will have a look. Please
> give us some time, I think it will not be able to match your pace :-)
>
> On Thu, Mar 24, 2011 at 7:39 PM, Vajda <vladava...@gmail.com> wrote:
> > I sent pull request with bug fixture.
> > And provided feature file with test in RuntimeTest to test this
> > problem.
>
> > Please look at it.
> > I'm eager to hear your opinion.
>
> > regards,
>
> > Vajda
>
> --
> mail: jonas.ba...@gmail.com

Predrag Knežević

unread,
Mar 28, 2011, 4:01:36 AM3/28/11
to spec...@googlegroups.com
> I am still wondering how you would solve the problem when there are
> several subclasses for a baseclass at runtime ...  but it would be an
> improvement in any case.

You are right - having several subclases for a baseclass would make
you troubles, because some steps would appear multiple times. However,
this is not the scenario we are looking for: it is enough for us to
have single subclass (extended from a baseclass) defining all needed
steps within a test project.

Cheers,

Predrag

Jonas Bandi

unread,
Mar 28, 2011, 5:18:24 PM3/28/11
to spec...@googlegroups.com
Thanks. I looked at the pull request.
Thinking about it, I think we should go one step further. As Gaspar
mentioned above in the thread, it should be possible to have a
concrete baseclass with the [Binding] attribute and then a concrete
subclass with the [Binding] attribute.
I think that would be a common reuse scenario (ie. subclassing an
existing class with shared steps, that can also be used without
subclassing).

I tried to formulate the feature that would describe the behavior of specflow:

Feature: Using inherited step definitions
In order to use inheritance in my step definition classes
As a programmer that implements step definitions
I want SpecFlow to work with inherited steps in an intuitive way

Scenario: Abstract baseclass1 with binding attribute, no subclass
Then SpecFlow should fail and report an error

Scenario: Abstract baseclass2 with binding attribute, concrete
subclass3 with binding attribute
Then SpecFlow should instantiate subclass3
And call the base step on that instance3
And call the sub step on that instance3

Scenario: Abstract baseclass4 with no binding attribute, concrete
subclass5 with binding attribute
Then SpecFlow should instantiate subclass5
And call the base step on that instance5
And call the sub step on that instance5

Scenario: Concrete baseclass6 with binding attribute, concrete
subclass7 with binding attribute
Then SpecFlow should instantiate subclass7
And call the base step on that instance7
And call the sub step on that instance7

Scenario: Concrete baseclass8 with no binding attribute, concrete
subclass9 with binding attribute
Then SpecFlow should instantiate subclass9
And call the base step on that instance9
And call the sub step on that instance9

Scenario: Concrete baseclass10 with binding attribute, first
subclass11 with binding attribute, second subclass12 of first
subclass11 with binding attribute
Then SpecFlow should instantiate subclass12
And call the base step on that instance12
And call the sub step on that instance12

Scenario: Concrete baseclass13 with binding attribute, first
subclass14 of baseclass13 with binding attribute, second baseclass13
of with binding attribute
Then SpecFlow should fail and report an AmbiguousMatchError


What do you think?
jonas

2011/3/28 Predrag Knežević <ped...@gmail.com>:

--

Predrag Knežević

unread,
Mar 29, 2011, 3:48:50 AM3/29/11
to spec...@googlegroups.com
> I think that would be a common reuse scenario (ie. subclassing an
> existing class with shared steps, that can also be used without
> subclassing).

Yes, I think it is the good idea too. The formulated scenarios make
all sense, but some of them are perhaps harder to support :)

Cheers,

Predrag

Jonas Bandi

unread,
Mar 29, 2011, 4:05:33 AM3/29/11
to spec...@googlegroups.com
I will check with Gaspar.
I think for the upcoming release we could just switch from
DeclaringType to ReflectedType as Vajda showed in his pull request.
This would solve your scenarios and not be a breaking change.

In the next release we could then support the above scenarios.

2011/3/29 Predrag Knežević <ped...@gmail.com>:

--

Vajda

unread,
Mar 29, 2011, 8:04:07 AM3/29/11
to SpecFlow
Thanks Jonas.
You've made my day. :)

On Mar 29, 10:05 am, Jonas Bandi <jonas.ba...@gmail.com> wrote:
> I will check with Gaspar.
> I think for the upcoming release we could just switch from
> DeclaringType to ReflectedType as Vajda showed in his pull request.
> This would solve your scenarios and not be a breaking change.
>
> In the next release we could then support the above scenarios.
>
> 2011/3/29 Predrag Knežević <ped...@gmail.com>:
>
> >> I think that would be a common reuse scenario (ie. subclassing an
> >> existing class with shared steps, that can also be used without
> >> subclassing).
>
> >  Yes, I think it is the good idea too. The formulated scenarios make
> > all sense, but some of them are perhaps harder to support :)
>
> >  Cheers,
>
> > Predrag
>
> --
> mail: jonas.ba...@gmail.com

Jonas Bandi

unread,
Apr 6, 2011, 9:41:44 AM4/6/11
to spec...@googlegroups.com
Just to wrap things up.
This issue should be fixed in SpecFlow v1.6.

--
mail: jonas...@gmail.com

Reply all
Reply to author
Forward
0 new messages