Specflow Container of the steps class has not been initialized - c#

public class BaseSteps : Steps
{
[BeforeFeature]
public static void BeforeFeatureStep()
{
var otherStep = new OtherStep();
otherStep.ExecuteStep();
}
}
public class OtherStep : Steps
{
public void ExecuteStep()
{
var key = 'key';
var val = 'val';
this.FeatureContext.Add(key, val);
}
}
This is a sample snippet. When I try to access this.FeatureContext.Add(), I get an exception stating Container of the steps class has not been initialized
Any help on this is appreciated.

The FeatureContext is not initialized, because the Step class is not resolved by the SpecFlow DI Container. So the SetObjectContainer method is not called (https://github.com/techtalk/SpecFlow/blob/master/TechTalk.SpecFlow/Steps.cs#L10).
As a general rule, you should not instantiate the steps classes on your own, but get them via Context Injection (http://specflow.org/documentation/Context-Injection).
But that is not possible in your case because you are in a BeforeFeature hook.
A possible solution would be, that you use the latest pre-release of SpecFlow (https://www.nuget.org/packages/SpecFlow/2.2.0-preview20170523).
There you can get the FeatureContext via a parameter in the hook method.
It looks like this:
[BeforeFeature]
public static void BeforeFeatureHook(FeatureContext featureContext)
{
//your code
}
Your code could then look like this:
public class FeatureContextDriver
{
public void FeatureContextChanging(FeatureContext featureContext)
{
var key = 'key';
var val = 'val';
featureContext.Add(key, val);
}
}
[Binding]
public class BaseSteps : Steps
{
[BeforeFeature]
public static void BeforeFeatureStep(FeatureContext featureContext)
{
var featureContextDriver = new FeatureContextDriver();
featureContextDriver.FeatureContextChanging(featureContext);
}
}
[Binding]
public class OtherStep : Steps
{
private FeatureContextDriver _featureContextDriver;
public OtherStep(FeatureContextDriver featureContextDriver)
{
_featureContextDriver = featureContextDriver;
}
public void ExecuteStep()
{
_featureContextDriver.FeatureContextChanging(this.FeatureContext);
}
}
Code is not tested/tried out and applies the Driver Pattern.
Full Disclosure: I am one of the maintainers of SpecFlow and SpecFlow+.

Related

Log4net get correct class and method name in logfile using Ninject

I'm converting an application to use Ninject as IoC and one of the things I need to convert is the existing Log4net implementation. The problem that I'm facing is that in the logfile (I use the XmlLayoutSchemaLog4j pattern) the class and method name seems to be of the calling parent instead of the actual caller.
I checked the types that are given to the new Log4NetLogger() and they seem to be of the exact same type as you specify using the LogManager.GetLogger(Methodbase.GetCurrentMethod.DeclaringType);
I made a small program that uses the old and the new implementation to check the differences but I can't seem to find them.
the outcome of the program is this:
Every level is a specific log entry in the code and the first entry of that level is done via Ninject and the second is via de LogManager.
As you can see the logger is the same, but the class and method differs.
the code from the project is:
internal class Program
{
private static IDoSomething _something;
static void Main()
{
log4net.Config.XmlConfigurator.Configure();
Init();
_something.StartSomething();
}
private static void Init()
{
var kernel = new StandardKernel(new NinjectSettings { LoadExtensions = false });
kernel.Load(Assembly.GetExecutingAssembly());
_something = kernel.Get<IDoSomething>();
}
}
public class Bindings : NinjectModule
{
public override void Load()
{
Bind<ILogger>().ToMethod(x => new Log4NetLogger(x.Request.Target.Member.DeclaringType)).InTransientScope();
Bind<IDoSomething>().To<DoSomething>();
Bind<IDoSomethingElse>().To<DoSomethingElse>();
}
}
the dosomething:
public interface IDoSomething
{
void StartSomething();
}
public class DoSomething : IDoSomething
{
[Inject]
public ILogger Logger { get; set; }
public static ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
[Inject]
public IDoSomethingElse DoSomethingElse { get; set; }
public void StartSomething()
{
Logger.Debug("Start StartSomething");
Log.Debug("Start StartSomething");
DoSomethingElse.StartSomethingElse();
Logger.Fatal("End StartSomething");
Log.Fatal("End StartSomething");
}
}
And the DoSomethingElse
public interface IDoSomethingElse
{
void StartSomethingElse();
}
public class DoSomethingElse : IDoSomethingElse
{
[Inject]
public ILogger Logger { get; set; }
public static ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public void StartSomethingElse()
{
Logger.Info("Start Do Something Else");
Log.Info("Start Do Something Else");
StartSomethingLocal();
Logger.Error("End Do Something Else");
Log.Error("End Do Something Else");
}
private void StartSomethingLocal()
{
Logger.Warn("Start Do Something Local");
Log.Warn("Start Do Something Local");
Logger.Warn("End Do Something Local");
Log.Warn("End Do Something Local");
}
}
I tried several solutions for the type resolving in the new Log4NetLogger in the Load method but no luck.

Using Ninject, how can I use property injection, Lazy<>, and interception without encountering errors in castle.core?

I created a simple program as a PoC for an old SharePoint On-Prem project that uses ASP.NET Webforms. In its pages, I have to use property injection, and for everything else, I can use constructor injection. I am also using:
Ninject.Extensions.Factory
Ninject.Extensions.Interception
Ninject.Extensions.Interception.DynamicProxy
Everything was working relatively well until I added interceptors and used Lazy<> to tackle some cyclic dependencies. To simplify this in an example, I've written the following example as a console application:
public class Program
{
static void Main(string[] args)
{
IKernel kernel = new StandardKernel(
new NinjectSettings() { LoadExtensions = false },
new DynamicProxyModule(),
new FuncModule());
kernel.Bind<ISomeClass>().To<SomeClass>();
kernel.Bind<IOtherClass>().To<OtherClass>();
kernel.Bind<IAnotherClass>().To<AnotherClass>();
kernel.Intercept(p => true).With(new ClassInterceptor()); // Removing this works, but I need the interceptors.
ISomeClass someClass = kernel.TryGet<ISomeClass>();
someClass.Foo();
}
public interface ISomeClass
{
void Foo();
}
public class SomeClass : ISomeClass
{
[Inject]
public IOtherClass OtherClass { get; set; }
public SomeClass() { }
public void Foo()
{
Console.WriteLine("Foo");
this.OtherClass.Bar();
}
}
public interface IOtherClass
{
void Bar();
}
public class OtherClass : IOtherClass
{
private readonly Lazy<IAnotherClass> _anotherClass;
public IAnotherClass AnotherClass { get { return this._anotherClass.Value; } }
public OtherClass(Lazy<IAnotherClass> anotherClass)
{
this._anotherClass = anotherClass;
}
public void Bar()
{
Console.WriteLine("Bar");
}
}
public interface IAnotherClass
{
void FooBar();
}
public class AnotherClass : IAnotherClass
{
private readonly Lazy<IOtherClass> _otherClass;
public IOtherClass OtherClass { get { return this._otherClass.Value; } }
public AnotherClass(Lazy<IOtherClass> otherClass)
{
this._otherClass = otherClass;
}
public void FooBar()
{
Console.WriteLine("FooBar");
this.OtherClass.Bar();
}
}
public class ClassInterceptor: SimpleInterceptor
{
public ClassInterceptor() { }
protected override void BeforeInvoke(IInvocation invocation)
{
base.BeforeInvoke(invocation);
Console.WriteLine("I'm doing stuff before.");
}
protected override void AfterInvoke(IInvocation invocation)
{
base.BeforeInvoke(invocation);
Console.WriteLine("I'm doing stuff after.");
}
}
}
As a result, I am getting the following error:
Unhandled Exception: System.TypeLoadException: Could not load type 'Castle.Proxies.Func`2Proxy' from assembly 'DynamicProxyGenAssembly2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=a621a9e7e5c32e69' because the parent type is sealed.
If I remove the "Lazy<>", it will re-introduce cyclic dependencies. If I remove interception, it will not have any errors, but I need the interceptors. And, I have to use property injection on the pages because the constructors of the pages are managed by webforms with no helpful hooks like there are in MVC land. NOTE: webforms are being used because SharePoint 2013 is being used.
Any ideas how to keep both interception and Lazy<> declarations without encountering the error above?
I was able to resolve this by not adding the interceptors to the entire kernel as there were some types that could not have proxies created for them. Considering the exclusions lists were probably more than I was encountering, I chose the next best option which was to apply global interceptors individually to each binding:
static void Main(string[] args)
{
IKernel kernel = new StandardKernel(
new NinjectSettings() { LoadExtensions = false },
new DynamicProxyModule(),
new FuncModule());
AddInterceptors(kernel.Bind<ISomeClass>().To<SomeClass>());
AddInterceptors(kernel.Bind<IOtherClass>().To<OtherClass>());
AddInterceptors(kernel.Bind<IAnotherClass>().To<AnotherClass>());
//kernel.Intercept(p => true).With(new ClassInterceptor());
ISomeClass someClass = kernel.TryGet<ISomeClass>();
someClass.Foo();
}
private static void AddInterceptors<T>(IBindingWhenInNamedWithOrOnSyntax<T> binding)
{
binding.Intercept(p => true).With(new ClassInterceptor());
/* ... other interceptors ... */
}
Thanks for letting me know what was going with the interception extension trying to create a proxy for Lazy and T, #BatteryBackupUnit.
Any better solutions are welcomed!

Test Environment.Exit() in C#

Is there in C# some kind of equivalent of ExpectedSystemExit in Java? I have an exit in my code and would really like to be able to test it. The only thing I found in C# is a not really nice workaround.
Example Code
public void CheckRights()
{
if(!service.UserHasRights())
{
Environment.Exit(1);
}
}
Test Code
[TestMethod]
public void TestCheckRightsWithoutRights()
{
MyService service = ...
service.UserHasRights().Returns(false);
???
}
I am using the VS framework for testing (+ NSubstitute for mocking) but it is not a problem to switch to nunit or whatever for this test.
You should use dependency injection to supply to the class being tested an interface that provides an environmental exit.
For example:
public interface IEnvironment
{
void Exit(int code);
}
Let's also assume that you have an interface for calling UserHasRights():
public interface IRightsService
{
bool UserHasRights();
}
Now suppose your class to be tested looks like this:
public sealed class RightsChecker
{
readonly IRightsService service;
readonly IEnvironment environment;
public RightsChecker(IRightsService service, IEnvironment environment)
{
this.service = service;
this.environment = environment;
}
public void CheckRights()
{
if (!service.UserHasRights())
{
environment.Exit(1);
}
}
}
Now you can use a mocking framework to check that IEnvironment .Exit() is called under the right conditions. For example, using Moq it might look a bit like this:
[TestMethod]
public static void CheckRights_exits_program_when_user_has_no_rights()
{
var rightsService = new Mock<IRightsService>();
rightsService.Setup(foo => foo.UserHasRights()).Returns(false);
var enviromnent = new Mock<IEnvironment>();
var rightsChecker = new RightsChecker(rightsService.Object, enviromnent.Object);
rightsChecker.CheckRights();
enviromnent.Verify(foo => foo.Exit(1));
}
Ambient contexts and cross-cutting concerns
A method such as Environment.Exit() could be considered to be a cross-cutting concern, and you might well want to avoid passing around an interface for it because you can end up with an explosion of additional constructor parameters. (Note: The canonical example of a cross cutting concern is DateTime.Now.)
To address this issue, you can introduce an "Ambient context" - a pattern which allows you to use a static method while still retaining the ability to unit test calls to it. Of course, such things should be used sparingly and only for true cross-cutting concerns.
For example, you could introduce an ambient context for Environment like so:
public abstract class EnvironmentControl
{
public static EnvironmentControl Current
{
get
{
return _current;
}
set
{
if (value == null)
throw new ArgumentNullException(nameof(value));
_current = value;
}
}
public abstract void Exit(int value);
public static void ResetToDefault()
{
_current = DefaultEnvironmentControl.Instance;
}
static EnvironmentControl _current = DefaultEnvironmentControl.Instance;
}
public class DefaultEnvironmentControl : EnvironmentControl
{
public override void Exit(int value)
{
Environment.Exit(value);
}
public static DefaultEnvironmentControl Instance => _instance.Value;
static readonly Lazy<DefaultEnvironmentControl> _instance = new Lazy<DefaultEnvironmentControl>(() => new DefaultEnvironmentControl());
}
Normal code just calls EnvironmentControl.Current.Exit(). With this change, the IEnvironment parameter disappears from the RightsChecker class:
public sealed class RightsChecker
{
readonly IRightsService service;
public RightsChecker(IRightsService service)
{
this.service = service;
}
public void CheckRights()
{
if (!service.UserHasRights())
{
EnvironmentControl.Current.Exit(1);
}
}
}
But we still retain the ability to unit-test that it has been called:
public static void CheckRights_exits_program_when_user_has_no_rights()
{
var rightsService = new Mock<IRightsService>();
rightsService.Setup(foo => foo.UserHasRights()).Returns(false);
var enviromnent = new Mock<EnvironmentControl>();
EnvironmentControl.Current = enviromnent.Object;
try
{
var rightsChecker = new RightsChecker(rightsService.Object);
rightsChecker.CheckRights();
enviromnent.Verify(foo => foo.Exit(1));
}
finally
{
EnvironmentControl.ResetToDefault();
}
}
For more information about ambient contexts, see here.
I ended up creating a new method which I can then mock in my tests.
Code
public void CheckRights()
{
if(!service.UserHasRights())
{
Environment.Exit(1);
}
}
internal virtual void Exit()
{
Environment.Exit(1);
}
Unit test
[TestMethod]
public void TestCheckRightsWithoutRights()
{
MyService service = ...
service.When(svc => svc.Exit()).DoNotCallBase();
...
service.CheckRights();
service.Received(1).Exit();
}
If your goal is to avoid extra classes/interfaces just to support tests, how do you feel about Environment.Exit action via Property Injection?
class RightsChecker
{
public Action AccessDeniedAction { get; set; }
public RightsChecker(...)
{
...
AccessDeniedAction = () => Environment.Exit();
}
}
[Test]
public TestCheckRightsWithoutRights()
{
...
bool wasAccessDeniedActionExecuted = false;
rightsChecker.AccessDeniedAction = () => { wasAccessDeniedActionExecuted = true; }
...
Assert.That(wasAccessDeniedActionExecuted , Is.True);
}

Strongly typed metadata in MEF2 (System.Composition)

I'm using the System.Composition namespace from the MEF for web and Windows Store apps NuGet package in a new ASP.NET MVC4 project.
I've read that in MEF2 you no longer use Lazy<IExtension, IExtensionMetadata>, but now you must provide a concrete type for the metadata view (and possibly use ExportFactory<> instead of Lazy<> ?).
However, I can't find any examples of how this should all work - just a few mentions of using a concrete type instead of an interface.
I've tried a few things, but keep getting the following error - "Export metadata for 'AccountID' is missing and no default value was supplied".
My code...
Creating the container (in Global.asax or App_Start folder):
// Get assemblies that will be providing imports and exports
var assemblies = GetAssemblies();
// Get conventions that will be used to find imports and exports
var conventions = GetConventions();
var container = new ContainerConfiguration().WithAssemblies(assemblies, conventions).CreateContainer();
// Create and apply a MefControllerFactory so controllers can be composed
ControllerBuilder.Current.SetControllerFactory(new MefControllerFactory(container));
GetConventions() method:
private static ConventionBuilder GetConventions()
{
var conventionBuilder = new ConventionBuilder();
conventionBuilder.ForTypesDerivedFrom<IController>().Export();
conventionBuilder.ForTypesDerivedFrom<IExtension>().Export<IExtension>();
conventionBuilder.ForTypesMatching(t => t.Namespace != null && t.Namespace.EndsWith(".Parts")).Export().ExportInterfaces();
return conventionBuilder;
}
IExtension.cs:
public interface IExtension
{
void DoWork();
}
ExtensionMetadata.cs:
public class ExtensionMetadata
{
public int AccountID { get; set; }
}
ExtensionA.cs (same as ExtensionB.cs):
public void DoWork()
{
System.Diagnostics.Debug.WriteLine("ExtensionA doing work..");
}
ExtensionManager.cs:
public class ExtensionManager
{
private IEnumerable<ExportFactory<IExtension, ExtensionMetadata>> _extensions;
public ExtensionManager(IEnumerable<ExportFactory<IExtension, ExtensionMetadata>> extensions)
{
_extensions = extensions;
}
public void DoWork(int accountID)
{
foreach (var extension in _extensions)
{
if (extension.Metadata.AccountID == accountID)
{
extension.DoWork();
}
}
}
}
I think I'm missing something quite major here. Basically I want to lazily import all Extensions, check their metadata and if a condition is fulfilled have that extension do something.
Would really appreciate your feedback or any links to sample code / tutorials that cover my scenario.
Many thanks!
I think I've worked it out after reading this SO question.
I created a Metadata Attribute:
[MetadataAttribute]
public class ExtensionMetadataAttribute : ExportAttribute, IExtensionMetadata
{
public int AccountID { get; set; }
public ExtensionMetadataAttribute(int accountID) : base(typeof (IExtension))
{
AccountID = accountID;
}
}
Then modified ExtensionA.cs:
[ExtensionMetadata(1)]
public class ExtensionA : IExtension
{
public void DoWork()
{
System.Diagnostics.Debug.WriteLine("ExtensionA doing work..");
}
}
And now ExtensionManager.cs looks like this:
public class ExtensionManager : IExtensionManager
{
private readonly IEnumerable<ExportFactory<IExtension, ExtensionMetadata>> _extensions;
public ExtensionManager(IEnumerable<ExportFactory<IExtension, ExtensionMetadata>> extensions)
{
_extensions = extensions;
}
public void DoWork(int accountID)
{
foreach (var extension in _extensions)
{
if (extension.Metadata.AccountID == accountID)
{
using (var foo = extension.CreateExport())
{
foo.Value.DoWork();
}
}
}
}
}
This seems to do the trick, but I would still be interested in any feedback re best practices, performance issues etc.
Thanks!

MEF: Unable to import in other classes?

Edit: Matt, that does indeed solves some (most) of my problems, thank you. Now the only lingering issue of how do I do this in WPF? I have a custom part based off of a UserControl but there is no way in WPF to do :
[Import]<my:SomeCustomControl>
so the cascade doesn't work in this instance.
/Edit
I am having an issue [Import]ing various MEF components in my project. Do I have to use a CompositionContainer in every class I use? In the code below, a null reference exception is thrown in the method Helper.TimesTwo() but when I call logger.Log() in the Program class, everything works. Any help would be greatly appreciated.
(this will compile and run as a console app).
using System;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
var p = new Program();
p.Run();
}
[Import]
private ILog logger { get; set; }
public void Run()
{
var catalog = new DirectoryCatalog(".");
var container = new CompositionContainer(catalog);
var batch = new CompositionBatch();
batch.AddPart(this);
container.Compose(batch);
logger.Log("hello");
var h = new Helper();
logger.Log(h.TimesTwo(15).ToString());
Console.ReadKey();
}
}
class Helper
{
[Import]
private IDouble doubler { get; set; }
private Helper()
{
// do I have to do all the work with CompositionContainer here again?
}
public double TimesTwo(double d)
{
return doubler.DoubleIt(d);
}
}
interface ILog
{
void Log(string message);
}
[Export(typeof(ILog))]
class MyLog : ILog
{
public void Log(string message)
{
Console.WriteLine("mylog: " + message);
}
}
interface IDouble
{
double DoubleIt(double d);
}
[Export(typeof(IDouble))]
class MyDoubler : IDouble
{
public double DoubleIt(double d)
{
return d * 2.0;
}
}
}
I think the trick is to make use of the fact that MEF will cascade its imports. So if you import your Helper instance rather than declaring it as a local variable, any imports that the Helper requires will be satisfied.
[Import]
public Helper MyHelper { get; set; }
public void Run()
{
var catalog = new DirectoryCatalog(".");
var container = new CompositionContainer(catalog);
var batch = new CompositionBatch();
batch.AddPart(this);
container.Compose(batch);
logger.Log("hello");
logger.Log(MyHelper.TimesTwo(15).ToString());
Console.ReadKey();
}
I'm sure there's a way to have it satisfy any imports in a local variable, but I like using the "cascaded imports" feature like that.
No you can't do that. You could look into using attached properties though for this. With an attached property you can have the container compose the element that the attached property is added to. Another option would be markup extensions.
Glenn
Try changing
[Import]
private ILog logger { get; set; }
to
[Import]
public ILog logger { get; set; }
It might work.

Categories

Resources