Ambiguous step definitions when try to implement in generic fashion c#, specflow - c#

I have implemented code in following fashion.
public abstract class BaseDocumentStep<T> where T : class, new()
{
protected T _document;
[Given(#"I Add New '(.*)'")]
public void GivenIAddNew(string p0)
{
Console.WriteLine(p0);
}
}
[Binding]
public class CustomerSteps : BaseDocumentStep<Customer>
{
}
[Binding]
public class EmployeeSteps : BaseDocumentStep<Employee>
{
}
Feature Files :-
a) Customer Feature
Scenario: Add New Customer
Given I Add New 'Customer'
b) Employee Feature
Scenario: Add New Employee
Given I Add New 'Employee'
When I run these scenarios. I got following error :
-> binding error: Ambiguous step definitions found for step 'Given I Add New 'Customer'': BaseDocumentStep1.GivenIAddNew(String), BaseDocumentStep1.GivenIAddNew(String)
After Scenario
I am not able to figure out, why specflow consider this step as ambiguous ?
Thanks in Advance.
Adi.

Adi,
Are there any reasons you want to use the abstract class for your tests? I have been using specflow for a few years now, and I have always tried to keep them simple and linear. Can you try to replace your step definition file with this:
[Binding]
public class EmployeeSteps
{
[Given(#"I Add New '(.*)'")]
public void GivenIAddNew(string p0)
{
Console.WriteLine(p0);
}
}
this is working fine for me. This should work out fine unless you have other reasons not to keep your steps this simple.

The problem here is that in Specflow all steps are global, and so if you declare a step in a base class, that step is also declared in every derived class. So you get one instance of
[Given(#"I Add New '(.*)'")]
public void GivenIAddNew(string p0)
{
Console.WriteLine(p0);
}
in CustomerSteps and EmployeeSteps
Step binding methods should not be declared in base classes, the steps will always be able to be found due to the fact that they are global.
It's not exactly clear what you want to achieve with your generic design, but perhaps if you give a bit more information about that (probably another question is better) then we might be able to help you get to a solution that does not require inheritance with binding classes.

Related

Adding parameter to base class constructor, auto-add to all descendants

I am trying to improve some code to take out initialisations and use of the Service Locator in my View Model, so that the container can create them within the constructor. But there are changes to base classes that have hundreds of descendants and this will take a long time to manually fix everyone.
Is there a way that Visual Studio or any other add-in can do this for you? On the descendant it will need to add it into the main constructor and pass it through to the base constructor also. There is only a single constructor on all.
e.g. I have just added the someNewInjectedClass parameter to the base class constructor below:
public class BaseClass
{
private ISomeNewInjectedClass _someNewInjectedClass;
public BaseClass(ISomeNewInjectedClass someNewInjectedClass)
{
_someNewInjectedClass = someNewInjectedClass;
}
}
And that needs to be added to my descendant which is currently this:
public class OneOfManyDecendants : BaseClass
{
public OneOfManyDecendants()
: base()
{
}
}
To become this:
public class OneOfManyDecendants : BaseClass
{
public OneOfManyDecendants(ISomeNewInjectedClass someNewInjectedClass)
: base(someNewInjectedClass)
{
}
}
If you have Resharper you can use "Change Signature" (Ctrl+R,S) refactoring. When doing it select "Resolve with call tree" option. In a next dialog pick "Create parameter..." option for each subclass.
Not quite an answer to my exact question but I am going to go a long the lines of #sinatr's suggestion with this related post: Use class as a single parameter for base parameters
This seems the best way for us going forward and can more easily change in the future.

Simple inheritance does not work between projects

I just know I'm being an idiot, so somebody please tell me how.
Setup is simple:
Create a solution with three projects (.Net framework, class libraries) named InherTest, InherTest.Base, and InherTest.Base.Inherited
In InherTest.Base, add the following class:
namespace InherTest.Base
{
public abstract class BaseClass
{
internal abstract string MEMBER_1 { get; }
}
}
Copy the exact same code into InherTest, including the namespace.
In InherTest.Base.Inherited, add the following class:
namespace InherTest.Base.Inherited
{
public class Inherited : BaseClass
{
internal override string MEMBER_1 { get; }
}
}
Add a project reference in InherTest.Base.Inherited to InherTest.Base. Note the errors ("abstract member not implemented" and "no suitable member found to override").
Remove that reference and replace it with one to InherTest. Observe that the inheritance also fails.
Why don't they both work?
Edit: Originally I stated that one test would fail and the other would succeed; however, both inheritance attempts fail in the above scenario.
This is because the string is internal so limited to it's own project
Why don't they both work?
They should both fail if they contain the same code as you claim. If that is not the case then the code is different between the 2 projects, specifically the MEMBER_1 is probably declared as public in InherTest project.
The only way that a reference to InherTest would work with the same code you posted is if you have this assembly level attribute InternalsVisibleToAttribute in the project InherTest
[assembly:InternalsVisibleTo("InherTest.Base.Inherited")]
Inherited Namespaces are in different project. (Name spaces seems like together but they are not in a same assembly). You can read that article.
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/internal

Can I avoid Exporting LayerClass in Views derived from iPhoneOSGameView?

Given a class:
public class BaseGameView : OpenTK.Platform.iPhoneOS.iPhoneOSGameView {
Constructing BaseGameView at runtime will throw System.Exception: Failed to find selector layerClass... This is easily resolved by adding the following to the class definition:
[Export ("layerClass")]
public static new Class GetLayerClass()
{
return iPhoneOSGameView.GetLayerClass();
}
This is not so undesirable until I derive another class as follows:
public class DerivedGameView : BaseGameView {
Constructing the DerivedGameView also throws the same exception unless I Export("layerClass") from that class as well.
How can I DRY this out? I have a handful of these derived views and they all have to have the same snippet of code exporting the layer class... I'd rather not repeat it.
A related question is:
Why is this not necessary for a class simply derived from UIView?
Cheers!
This is currently a limitation inside MonoTouch - static methods from base classes aren't exported.
I have filed a bug report for this: https://bugzilla.xamarin.com/show_bug.cgi?id=6170 - you can CC yourself on this bug to get notified when it's fixed.

Error on implementing interface

This will likely (hopefully?) be an "amateur hour" type question. :)
I'm new to interfaces, etc. and doing things correctly, but I have an MVC 3 project that references a C# library project.
In the C# library project, I have the following code:
public interface IRepositoryAddable<T>
{
void Add(T entity);
}
I repeat this sort of code for other types of repository so that I can make things easier and standard across all my repositories.
For example, I have a repository for anything of type "ISkill":
public interface ISkillRepository : IRepositoryAddable<ISkill>, IRepositoryDeleteable<ISkill>, IRepositoryDeleteableByID<ISkill, int>, IRepositoryGettableByID<ISkill, int>, IRepositoryListable<ISkill>, IRepositorySavable<ISkill>
{ }
Then, in my actual repository, I have:
public class SkillRepository : ISkillRepository
{
public void Add(Skill skillToAdd)
{
return;
}
}
As far as I'm aware, this should suffice to implement the ISkillRepositoryListable interface. However, I receive the following error:
Error 5 'DakotaSkills.MVC.Models.Repository.SkillRepository'
does not implement interface member
'DakotaSkills.Lib.Interfaces.Repository.IRepositoryAddable.Add(DakotaSkills.Lib.Interfaces.ISkill)' C:\Users\Sean\Projects\Web\DakotaSkills\src\DakotaSkills.MVC\Models\Repository\SkillRepository.cs 11 18 DakotaSkills.MVC
Other interface methods for the repository have shown as being implemented fine and I'm not quite sure what I'm doing wrong. For the record, my "Skill" type implements "ISkill" and I receive no error on its implementation.
Help?
Thanks!
Your Add would not accept some other class that also implemented ISkill. You need to take an ISkill, not just a Skill. That also suggests that your implementation of Add, should it ever do anything, should do so through ISkill only and not by calling other Skill methods you may know about.
You've defined the interface as having:
void Add(ISkill skillToAdd)
but, you're implementing
void Add(Skill skillToAdd)
which means they don't match. If I have a different ISkill implementation, I can't use your SkillRepository.
You either need to make SkillRepository work with any ISkill, or change your ISkillRepoistory interface to use a concrete Skill as its type parameters.
Should be:
public class SkillRepository : ISkillRepository
{
public void Add(ISkill skillToAdd)
{
return;
}
}
Skill is a more specific type than ISkill, so I think you need to change your implementation of Add to accept ISkill, rather than Skill:
public void Add(ISkill skillToAdd)
{
return;
}
I'd need to see your call site, i.e. the calling code
However this sounds too complicated. Read this and have a think http://ayende.com/Blog/archive/2011/03/24/the-wages-of-sin-hit-that-database-one-more-timehellip.aspx

Passing a derived class to a web service method that takes an abstract type

I have a bizarre problem that is doing my head in.
I have the following classes defined in a single project:
public abstract class AbstractUnitModel {
public void executeRemoteModel(){}
}
//this class also implements a seperate interface, but I dont think that is the issue
public class BlastFurnaceUnitModel : AbstractUnitModel, IUnitModel {}
Now if I try something like this, it works as expected:
class Class1
{
public void method1() {
BlastFurnaceUnitModel b = new BlastFurnaceUnitModel();
method2(b);
}
public void method2(AbstractUnitModel a) {}
}
Now I have another project that exposes a web method. This method takes an AbstractUnitModel and executes it remotely, then sends the results back to the client. So on the server I have this:
[WebMethod]
public AbstractUnitModel remotelyExecuteUnitModel(UnitModelWrapperInterface.AbstractUnitModel unitModel)
{
unitModel.executeRemoteModel();
return unitModel;
}
And on the client I have this:
public void remoteExecution() {
var unitModelWebService = new UnitModelRemoteServer.RemoteModelExecutionWebService();
unitModelWebService.remotelyExecuteUnitModelCompleted += new UnitModelRemoteServer.remotelyExecuteUnitModelCompletedEventHandler(remoteExecutionCompleted);
unitModelWebService.remotelyExecuteUnitModelAsync(this.remoteBF);
}
But my project will not compile, and I get these errors:
Error 109 The best overloaded method match for 'CalibrationClient.UnitModelRemoteServer.RemoteModelExecutionWebService.remotelyExecuteUnitModelAsync(CalibrationClient.UnitModelRemoteServer.AbstractUnitModel)' has some invalid arguments
Error 110 Argument '1': cannot convert from 'UnitModelWrapperInterface.BlastFurnaceUnitModel' to 'CalibrationClient.UnitModelRemoteServer.AbstractUnitModel'
I can not figure out why this is happening. I have references in the server project to the namespace where AbstractUnitModel is defined. The only thing that looked a little funny to me is that it is using AbstractUnitModel from the 'CalibrationClient' namespace rather than the UnitModelWrapperInterface. It seems when VS generates the proxy for a webservice on the client it creates a partial abstract implementation of AbstractUnitModel. Is this the source of my problem? If so, how might I go about fixing it?
edit for solution: As pointed out, the client needs to know about all classes that could be sent across the wire. I ended up solving this by removing the generated proxy classes and referencing the common library. Not ideal but good enough in this situation.
This happens because the WSDL tool creates proxy classes (open the service code file and you'll see them) which are the classes used to instantiate when objects come from the service.
If you want to avoid this, it's best to use WCF. This also deals with the polymorphic returned objects, as webservices also can't deal with polymorphism (so the return type of the remotelyExecuteUnitModel method is always AbstractUnitModel.
You might try [XmlInclude]:
[XmlInclude(typeof(BlastFurnaceUnitModel))]
public abstract class AbstractUnitModel {...}
Worth a try, at least...
(edit) Or at the method level:
[WebMethod(), XmlInclude(typeof(BlastFurnaceUnitModel))]
public AbstractUnitModel remotelyExecuteUnitModel(...) {...}
(less sure about the second)
The class exposed in your WebService is created in a different namespace inside your service reference.
I usually create a method like
WebServiceReferenceNS.AbstractUnitModel ToWebServiceModel(AbstractUnitModel unitModel)
{
}
to prepare the classes for the WebService. But I'd like to see if there's a more elegant solution.

Categories

Resources