We're using Unity as our dependency injection framework.
I want to create an acceptance test and need an instance of DossierService.
Unfortunately I get the following exception:
BoDi.ObjectContainerException: 'Interface cannot be resolved [...]'
[Binding]
public class DossierServiceSteps : BaseSteps
{
private IDossierService dossierService;
public DossierServiceSteps(IDossierService dossierService)
{
this.dossierService = dossierService;
}
}
What exactly is BoDi? I can't find any useful information..
How can I tell SpecFlow to use the normal Unity container?
Thanks in advance
Edit:
I've tried using SpecFlow.Unity like so:
public static class TestDependencies
{
[ScenarioDependencies]
public static IUnityContainer CreateContainer()
{
var container = UnityConfig.GetConfiguredContainer();
container.RegisterTypes(typeof(TestDependencies).Assembly.GetTypes().Where(t => Attribute.IsDefined(t, typeof(BindingAttribute))),
WithMappings.FromMatchingInterface,
WithName.Default,
WithLifetime.ContainerControlled);
return container;
}
}
In UnityConfig the types are correctly registered
container.RegisterType<IDossierService, DossierService>(new InjectionConstructor(typeof(IDataService), typeof(IDossierRepository), typeof(IDbContext), true));
But I still get the same exception. When I put a breakpoint at the start of the CreateContainer() method of TestDependencies it doesn't break...
For anyone looking for available plugins/libraries that support DI in Specflow project: https://docs.specflow.org/projects/specflow/en/latest/Extend/Available-Plugins.html#plugins-for-di-container
I prefer - https://github.com/solidtoken/SpecFlow.DependencyInjection
Example
Create DI container:
[ScenarioDependencies]
public static IServiceCollection CreateServices()
{
var services = new ServiceCollection();
Config config = JObject.Parse(File.ReadAllText("config.json")).ToObject<Config>();
services.AddSingleton(config);
services.AddScoped<DbConnections>();
services.AddScoped<ApiClients>();
return services;
}
Consume dependencies (via parameterized constructors):
[Binding]
public sealed class CalculatorStepDefinitions
{
private readonly DbConnections dbConnections;
public CalculatorStepDefinitions(DbConnections dbConnections) => this.dbConnections = dbConnections;
...
}
We solved this problem by implementing SpecFlow RuntimePlugin. In our case it was Castle.Windsor, but principle is the same. First you define the plugin which override default SpecFlow Instance Resolver:
public class CastleWindsorPlugin : IRuntimePlugin
{
public void Initialize(RuntimePluginEvents runtimePluginEvents, RuntimePluginParameters runtimePluginParameters)
{
runtimePluginEvents.CustomizeScenarioDependencies += (sender, args) =>
{
args.ObjectContainer.RegisterTypeAs<CastleWindsorBindingInstanceResolver, IBindingInstanceResolver>();
};
}
}
Where in CastleWindsorBindingInstanceResolver we needed to implement single method: object ResolveBindingInstance(Type bindingType, IObjectContainer scenarioContainer);. This class contains container and resolution (in your case instance of IUnityContainer. I recommend to inject to the container instance of self, so that you could inject the instance of IUnityContainer to SpecFlow binding classes)
This plugin needs to be in separate assembly and you load that to your test project like adjusting app.config like this:
<specFlow>
<plugins>
<add name="PluginAssemblyName" path="." type="Runtime" />
</plugins>
...
</specFlow>
What exactly is BoDi? I can't find any useful information..
BoDI is a very basic Dependency Injection framework that ships within Specflow. You can find its code repository here.
See this entry from the blog of SpecFlow's creator, Gáspár Nagy (emphasis mine):
SpecFlow uses a special dependency injection framework called BoDi to handle these tasks. BoDi is an embeddable open-source mini DI framework available on GitHub. Although it is a generic purpose DI, its design and features are driven by the needs of SpecFlow. By the time the SpecFlow project started, NuGet had not existed yet, so the libraries were distributed via zip downloads and the assemblies had to be referenced manually. Therefore we wanted to keep the SpecFlow runtime as a single-assembly library. For this, we needed a DI framework that was small and could be embedded as source code. Also we did not want to use a well-known DI framework, because it might have caused a conflict with the version of the framework used by your own project. This led me to create BoDi.
You can find an example of how to register types and interfaces in BoDI here:
[Binding]
public class DependencyConfiguration
{
private IObjectContainer objectContainer;
public DependencyConfiguration(IObjectContainer objectContainer)
{
this.objectContainer = objectContainer;
}
[BeforeScenario(Order = 0)]
public void ConfigureDependencies()
{
if (...)
objectContainer.RegisterTypeAs<RealDbDriver, IControllerDriver>();
else
objectContainer.RegisterTypeAs<StubDbDriver, IControllerDriver>();
}
}
However, be warned that (in the words of Gáspár Nagy):
Although it is possible to customize the dependency injection used by SpecFlow, it already scratches the boundaries of BoDi’s capacity. A better choice would be to use a more complex DI framework for this.
In this situation usually you should use Mock of your Interface.
Related
I want to add a custom test reporter to NUnit. I already did it with NUnit2, but I now need to use NUnit3.
To implement the reporter, I need to get various events from the framework, like start, end and failure of tests.
In NUnit2 I used NUnitHook to register my EventListener and it worked pretty good.
In NUnit3 I need to use the extension point mechanism, but when I add the extension point to the project, VisualStudio (2012 ultimate) immediately fails to discover the NUnit tests.
[TypeExtensionPoint(Description = "Test Reporter Extension")]
public class MyTestEventListener : ITestEventListener
{
public void OnTestEvent(string report)
{
Console.WriteLine(report);
}
}
If I remove the ITestEventListener implementation declaration from the class, it rediscovers the tests perfectly.
[TypeExtensionPoint(Description = "Test Reporter Extension")]
public class MyTestEventListener //: ITestEventListener
{
public void OnTestEvent(string report)
{
Console.WriteLine(report);
}
}
Am I doing something wrong? is there a better way to achieve it?
You don't say where you are putting this code, but I am suspecting it's in your test assembly. If so, that's not where it belongs. NUnit engine extensions get installed into the NUnit engine, so they need to be in a separate assembly. Once you have a separate assembly, you need to tell the engine where it is. Currently, you do this by creating a file of type .addins in the same directory as the engine. (You could modify the existing file, but that introduces maintenance problems in the future)
A future release will have an easier way to install addins, but they will continue to be entirely separate from your tests.
A further problem is that you are using TypeExtensionPointAttribute. I didn't notice this originally in your code and it's probably the biggest error so I'm adding this info now.
An "ExtensionPoint" is the thing you are extending. NUnit defines ExtensionPoints, while you create Extenisons to extend them. TypeExtensionPointAttribute is used inside NUnit to define extension points. It's not used by you. You use the ExtensionAttribute to define your extension.
Your extension should be defined something like this:
[Extension(Description = "Test Reporter Extension", EngineVersion="3.4")]
public class MyTestEventListener : ITestEventListener
{
public void OnTestEvent(string report)
{
Console.WriteLine(report);
}
}
You don't say what version of NUnit you are running. Test Listeners are only supported beginning with version 3.4. The EngineVersion property above is purely documentary at this point, because 3.4 is also the first version to recognize it.
There is a new writeup in the NUnit docs that may be helpful: https://github.com/nunit/docs/wiki/Writing-Engine-Extensions
Unfortunately I have a Specflow test passing locally, but it fails on the VSO Build vNext server, and I really need to see verbose information during the test run so I can figure out what is going on.
But I'm struggling to try to inject ITestOutputHelper into a Specflow binding like so
public SomeSteps(ITestOutputHelper outputHelper)
but Specflow complains with the message
BoDi.ObjectContainerException Interface cannot be resolved: Xunit.Abstractions.ITestOutputHelper (resolution path: ...)
How on earth can view log and view output during a Specflow test?
not sure if I'm using a newer version and it's easier now, but this seems to work for me:
ScenarioContext.Current.ScenarioContainer.Resolve<ITestOutputHelper>().WriteLine("Hello");
This is the best I could come up with, it's not ideal but it does accomplish what you want.
You create a new class that implements your generated xunit class. In my example, the generated class is called YourNormalFeatureClass
public class SpecialTest : YourNormalFeatureClass
{
private Xunit.Abstractions.ITestOutputHelper helper;
public SpecialTest(ITestOutputHelper helper) : base()
{
this.helper = helper;
}
public override void ScenarioSetup(ScenarioInfo scenarioInfo)
{
base.ScenarioSetup(scenarioInfo);
// you'd want a better way to keep track of this string
TechTalk.SpecFlow.TestRunnerManager.GetTestRunner().ScenarioContext.Set(this.helper, "helper");
}
}
Now, you're able to access your XUnit ITestOutputHelper from within your steps file via
var helper = this._scenarioContext.Get<Xunit.Abstractions.ITestOutputHelper>("helper");
helper.WriteLine("output from within the steps file that will be written to xunit!");
You'd need to be defensive with that helper variable to make sure that you don't get any NullReferenceException's
The downside to this is that you now have 2 copies of the same test because you inherited the old test. So in this case you have the tests from SpecialTest and YourNormalFeatureClass. This means that you'd need to not run YourNormalFeatureClass tests and only run the SpecialTest tests.
All of this would be easily solved if SpecFlow allowed you to customize the code generation process. That way you could expose the ITestOutputHelper via the generated code. The consumption of it from within the steps would be the same.
This may be a new addition to SpecFlow since this question was asked (6 years ago), but TechTalk.SpecFlow.Infrastructure.ISpecFlowOutputHelper should solve your problem. Inject it and use it in much the same way you would with xUnit's ITestOutputHelper, e.g.
[Binding]
public class SomeSteps
{
private readonly ISpecFlowOutputHelper output;
public SomeSteps(ISpecFlowOutputHelper output)
{
this.output = output;
}
[When(#"I write some debug info")]
public void WhenIWriteSomeDebugInfo()
{
this.output.WriteLine("Hello world!");
}
}
I'm trying out Ninject's Logging extension (v3.0) with NLog (v2.0) and, from what I've read, I'm not supposed to configure anything, the thing is like auto-magical and all I need to do is declare a ILogger dependency wherever I need one.
I kept the nlog.config file I already had, and removed all code that created loggers and instead put ILogger in my classes' constructors.
I'm getting an ActivationException at the composition root, ...Ninject can't resolve ILogger.
What am I missing?
What I have essentially boils down to this:
public static void Main(string[] args)
{
// nothing special here, binds IMyApp to MyApp.
using (var kernel = new StandardKernel(new NinjectConfig()))
{
var app = kernel.Get<IMyApp>(); // MyApp has a ILogger dependency **blows up here**
app.Run(args);
}
}
This is a console app, for what it's worth... Is the logging extension supposed to work like this?
The documentation says:
make sure you have the kernel load a new Log4NetModule or NLogModule before requesting the type instance
But if I do this:
using (var kernel = new StandardKernel(new NLogModule(), new NinjectConfig()))
{
...
...ReSharper doesn't know what NLogModule is.
Downloading the nuget package for Ninject.Extensions.Logging isn't enough.
You also need to download the nuget package for Ninject.Extensions.Logging.nlog2, which contains the NLogModule class that's needed to bind the ILogger interface.
There's also an available nuget package for log4net logging available.
This:
var kernel = new StandardKernel(new NinjectConfig())
Is all that's required to make everything work - no need to explicitly load a new NLogModule().
We are wrapping an existing logging library in our own logging service in a C# application to surround it with predefined methods for certain logging situations.
public class LoggingBlockLoggingService : ILoggingService
{
private LogWriter writer;
public LoggingBlockLoggingService(LogWriter writer)
{
this.writer = writer;
}
....//logging convenience methods, LogWarning(), etc...
}
I would like to modify this implementation so that it takes in the Type of the class that instantiates it (the underlying logger, LogWriter in this case, would be a singleton). So either make this implementation (and the interface ILoggingService) generic:
public class LoggingBlockLoggingService<T> : ILoggingService<T>
{
...
private string typeName = typeof(T).FulName;
...
Or add an additional constructor parameter:
public class LoggingBlockLoggingService : ILoggingService
{
private LogWriter writer;
private string typeName;
public LoggingBlockLoggingService(LogWriter writer, Type type)
{
this.writer = writer;
this.typeName = type.FullName;
}
....//Include the typeName in the logs so we know the class that is logging.
}
Is there a way to configure this once in Unity when registering our types? I'd like to avoid having to add an entry for every class that wants to log. Ideally, if someone wants to add logging to a class in our project, they'd just add an ILoggingService to the constructor of the class they are working in, instead of adding another line to our unity config to register each class they are working on.
We are using run time/code configuration, not XML
Yes, you can use:
container.RegisterType(typeof(IMyGenericInterface<>), typeof(MyConcreteGenericClass<>));
In your case, when there's simple direct generic-param--to--generic-param mapping the Unity maybe actually handles that, but I doubt that any more advanced cases are not handled, because something at some point of time must provide the mapping of generic-parameters between the types (liek reordering Key-Value vs. Value-Key etc).
If Dave's answer is not enough, I'm fairly sure that you could write a plugin to Unity/ObjectBuilder that would register a new strategy or set of strategies that would cover just any type mapping you would like, including automatic assembly scanning or materialization of generics.
See the series of articles at http://www.orbifold.net/default/unity-objectbuilder-part-ii/ and the section near
Context.Strategies.AddNew< buildkeymappingstrategy >(UnityBuildStage.TypeMapping);
I've an API DLL (API.dll, for example) which, in addition to many other thinks, makes available an abstract class (AbstractClass).
Now making use of that AbstractClass I've implemented it on two different dlls:
First.API.Implementation.dll with ConcreteImplementation1
Second.API.Implementation.dll with ConcreteImplementation2
Both ConcreteImplementation1 and ConcreteImplementation2 are implementation of the same abstract class.
What I want is an application where I can choose which of those two dlls to use and, through that, choose which implementation to use without the user having to change anything within the code and, if possible, without stopping the application.
Some configuration file where I can bring the application to use whatever implementation I want. Something like:
<appconfiguration>
<implementation_to_use>
<dll>First.API.Implementation.dll</dll>
<class>ConcreteImplementation1</class>
</implementation_to_use>
</appconfiguration>
I know near to nothing about dependency injection, apart from its concept, but I guess thats the perfect fit for this task.
I've researched several DI/IoC libraries but I'm not familiar with all the concepts and names. I can use whatever library I want. For what I can say these are the most used: StructureMap, Ninject and Sprint.NET
Moreover, apart from all the dlls and implementation I need to indicate a file to be used by that application. Can I indicate its path in that same file?
I just need some tips and directions to implement such a thing. Some examples using one of those libraries, would be awesome.
Thanks.
To get you started using StructureMap, create a console application, include in it:
structuremap.config:
<?xml version="1.0" encoding="utf-8" ?>
<StructureMap MementoStyle="Attribute">
<DefaultInstance
PluginType="DemoIoC.AbstractBase,DemoIoC"
PluggedType="DemoIoC.ConcreteImplementation1,DemoIoC"
Scope="Singleton" />
</StructureMap>
The PluginType and PluggedType attributes are "FullyQualifiedClassName,AssemblyName"
By default it will look for assemblies in the executable folder, I'm not sure how you would specify another location for the assemblies
There are plenty of options for Scope, e.g. Singleton, Transient, etc
Program.cs:
namespace DemoIoC
{
using System;
using StructureMap;
public static class Program
{
public static void Main(string[] args)
{
// here you initialize structuremap from the config file.
// You could probably use a FileSystemWatcher to reinitialize
// whenever the structuremap.config file changes
ObjectFactory.Initialize(x =>
{
x.UseDefaultStructureMapConfigFile = true;
});
var concrete = ObjectFactory.GetInstance<AbstractBase>();
concrete.Method1();
Console.ReadKey(true);
}
}
}
AbstractBase.cs:
namespace DemoIoC
{
public abstract class AbstractBase
{
public abstract void Method1();
}
}
ConcreteImplementation1.cs:
namespace DemoIoC
{
using System;
public class ConcreteImplementation1 : AbstractBase
{
public override void Method1()
{
Console.WriteLine("Called ConcreteImplementation1");
}
}
}