Prism.Ninject 7.1.0.431
Prism 7.1.0.431
NUnit 3.3.3
NSubstitute
Previously using Prism 6.3 we had a set of unit test to confirm that we had all of our bindings in place as follows
protected IKernel TestKernel;
[SetUp]
public void Given
{
TestKernel = new StandardKernel();
SUT = new MyModule( TestKernel );
Core = Assembly.Load( "MyDLL.Core" ).GetTypes();
Common = Assembly.Load( "MyDLL.Common" ).GetTypes();
SUT.Initialize();
}
[ Test ]
public void Then_ViewModels_Will_Be_Bound()
{
var testCollection = Common
.Where( item => item.IsPublic )
.Where( item => item.Name.EndsWith( "ViewModel" ) );
foreach ( var item in testCollection )
{
Assert.That( TestKernel.GetBindings( item ).Any, $"Test Failed: {item.Name}" );
}
}
However in Ninject 7.1, the IModule interface has changed somewhat, so now parts are registered differently in
public void RegisterTypes(
IContainerRegistry containerRegistry )
I'm just trying to get my unit tests up and running again with this new IModule format. I had tried changing my given to be as follows
protected override void Given()
{
TestKernel = new StandardKernel();
TestContainerRegistry = Substitute.For<IContainerRegistry>();
TestContainerRegistry.GetContainer().Returns( TestKernel );
SUT = new MyModule();
}
However I get the following when I attempt to run my tests.
System.InvalidCastException : Unable to cast object of type 'Castle.Proxies.IContainerRegistryProxy' to type 'Prism.Ioc.IContainerExtension`1[Ninject.IKernel]'.
If anyone has any idea how I might be able to mock this it would be appreciated, as I'm currently at an impasse.
How you should test is always a hot topic full of disagreement, so I will try to give you some general information here. Prism.Ninject implements the container abstractions with the Prism.Ninject.Ioc.NinjectContainerExtension. This has two constructors, a default and one that allows you to pass in a specific Kernel.
Prism also implements extension methods for each of the containers to pull the container from the abstraction. You can achieve this in a couple of ways:
containerRegistry.GetContainer().SomeContainerSpecificApi()
Alternatively you could do:
var app = new MyApp();
app.Container.GetContainer().SomeContainerSpecificApi();
Again there are a variety of ways that you could implement your tests and I'm not about to get into how you should test. I will however say that in the event you don't want to create an app and you're just looking to validate that your types are registered for a Prism Module you might try something like:
var containerExtension = new NinjectContainerExtension();
var module = new MyModule();
module.RegisterTypes(containerExtension);
Assert.IsTrue(containerExtension.Instance.IsRegistered<MyType>());
I think I've figured it out (or made progress at least)
Instead of substituting with IContainerRegistry I had to use the following
protected override void Given()
{
TestKernel = new StandardKernel();
TestContainerRegistry = Substitute.For<IContainerExtension<IKernel>>();
TestContainerRegistry.GetContainer().Returns( TestKernel );
SUT = new MyModule();
}
Although it looks like I'm going to have to make more substitutes etc in order to have the containerRegistry.Register (etc) wind up in my TestKernel for verification.
Related
I just changed my [RegularExpression] validation and a third of my unit tests broke!
It turns out AutoFixture is generating values based on that regex, which is cool, but it doesn't understand all regexs, so I'd like to supply it with a simpler one:
Fixtures.Customize<Details>(c => c.With(d => d.PhoneNumber,
new SpecimenContext(Fixtures).Resolve(
new RegularExpressionRequest(#"[2-9]\d{2}-\d{3}-\d{4}"))));
This ends up giving me a generic LINQ error ("Sequence contains no elements.") at object creation time. What am I doing wrong?
Alternatively, is there any way I can just turn this feature off? Customize() is helpful, but it prevents me from using Build() without repeating all the same logic. (Doesn't it?)
You can't easily turn that feature off, but you can easily override it:
public class Details
{
[RegularExpression(#"?(?:\(\s*([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9])\s*\)|([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9]))\s*(?:[.-]\s*)?)?([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2})\s*(?:[.-]\s*)?([0-9]{4})(?:\s*(?:#|x\.?|ext\.?|extension)\s*(\d+))?$")]
public string PhoneNumber { get; set; }
}
public class DetailsTests
{
[Fact]
public void OverridePhoneNumberRegularExpression()
{
var fixture = new Fixture();
var pattern = #"[2-9]\d{2}-\d{3}-\d{4}";
var phoneNumber =
new SpecimenContext(fixture).Resolve(
new RegularExpressionRequest(pattern));
fixture.Customize<Details>(c => c
.With(x => x.PhoneNumber, phoneNumber));
var sut = fixture.Create<Details>();
var actual = sut.PhoneNumber;
Assert.True(Regex.IsMatch(actual, pattern));
}
}
This test passes and looks similar to the one shown in the question. – What other members are defined in Details class?
Running into a knowledge gap, been out of WinForms for so long, unsure if i am doing this correctly for Castle Windsor.
For the last 5 years i have developing ASP.Net applications (WebForms, MVC, etc). I now have a project where a web interface is not a viable solution, yet. So we are doing it with WinForms.
With Asp.Net, i would have just set up the Castle Windsor Container, CWC, static class and everything would have taken care of itself for Dependency Injections, etc.
I am having some issues when it comes to WinForms. I evidently cant implement the same rules for Dependency Injection that i did for the WebForms developments.
Current Implementation:
Program.cs:
static void Main () {
Initialize();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault( false );
var form = CWC.Resolve<frmMain>();
Application.Run( form );
}
public static void Initialize ( string log4netPath = null ) {
var container = new WindsorContainer();
container.Kernel.ComponentModelCreated += ( s => {
if ( s.LifestyleType == LifestyleType.Undefined )
s.LifestyleType = LifestyleType.PerWebRequest;
} );
container.Install(
new CoreManagerInstaller() ,
new DomainInstaller() ,
new RepositoryInstaller() ,
new ServiceInstaller()
);
//Installer for MVC framework -- Must be done after other installers on its own.
container.Install( new AppInstaller() );
if ( log4netPath != null ) {
//container.AddFacility( new LoggingFacility( LoggerImplementation.Log4net , log4netPath ) );
}
CWC.Init( container );
}
AppInstaller:
public class AppInstaller : IWindsorInstaller {
#region IWindsorInstaller Members
public void Install ( IWindsorContainer container , IConfigurationStore store ) {
container.Register(
Classes.FromThisAssembly()
.BasedOn<CIMForm>().LifestyleTransient() ,
Classes.FromThisAssembly()
.BasedOn<CIMTabControl>().LifestyleTransient() ,
Classes.FromThisAssembly()
.BasedOn<CIMTabPage>().LifestyleTransient() ,
Classes.FromThisAssembly()
.BasedOn<UserControl>().LifestyleTransient() );
}
#endregion
}
All the above is nothing new or problematic atm.
The problem child is the UserControl i am trying to reference Interfaces form other libraries. In WebForms i would have just dropped the Property signature and started using in the Event/Methods i needed it.
As such:
public partial class ClientInformationControl : UserControl {
public IServerRepository ServerRepository { get; set; }
private void ClientInformation_Load ( object sender , EventArgs e ) {
var servers = ServerRepository.Find().Select( s => new { Key=s.Id , Value=s.Name } );
cboServers.Items.AddRange( servers.ToArray() );
}
}
But ServerRepository never gets instantiated in this design. I have to manually call CWC.Resolve<IServerRepository>() in order for the property to have the information in need.
Is there a way to make it so that ServerRepository is automatically (auto-magically) filled with the object data from the container?
Tried doing public ClientInformationControl(IServerRepository serverRepo){} but the assignment did not persist past the constructor, so when the Control.Load event was triggered the ServerRepository Property has been emptied out.
The problem with usercontrols is that they do no get resolved by the DI framework (DIF).
You havent posted the code of your winform, but I assume the designer code looks something like this:
private void InitializeComponent()
{
this.ClientInformationControl1 = new ClientInformationControl();
[...]
}
This is because you probably dragged the user control onto the form, so the DIF does not know about it.
There are multiple ways to work around this:
1: Don't use the designer to add usercontrols, but register them and let the DIF resolve them for you. You can do this by adding them to the constuctor parameters, as property, or resolve the usercontrol whenever you need it.
2: Give the parent that is resolved (the form) a IServerRepository dependency. But then you'll have to manually wire the IServerRepository into the usercontrol tho...
Currently, I'm using custom made fake objects that behind the scenes use NSubstitute which creates the actual objects but it's becoming very hard to maintain as the project grows, so I'm trying to find alternatives and I'm hoping that AutoFixture is the right tool for the job.
I read the documentation and I'm struggling because there's very little to no documentation and I read most of the blog posts by Mark Seemann including the CheatSheet.
One of the things that I'm having hard time to grasp is how to create an object with a constructor that have parameters, in my case I need to pass argument to CsEmbeddedRazorViewEngine as well as HttpRequestBase to ControllerContext.
The way I see it is that I need to create a fake objects and finally create a customization object that injects them to
I also looked into NBuilder it seems slightly more trivial to pass arguments there but I've heard good things about AutoFixture and I would like to give it a try. :)
I'm trying to reduce the amount of fake objects I have so here is a real test, how can I do the same thing with AutoFixture?
[Theory,
InlineData("en-US"),
InlineData("en-us"),
InlineData("en")]
public void Should_return_the_default_path_of_the_view_for_enUS(string language)
{
// Arrange
const string EXPECTED_VIEW_PATH = "~/MyAssemblyName/Views/Home/Index.cshtml";
CsEmbeddedRazorViewEngine engine = CsEmbeddedRazorViewEngineFactory.Create(ASSEMBLY_NAME, VIEW_PATH, string.Empty);
string[] userLanguage = { language };
HttpRequestBase request = FakeHttpRequestFactory.Create(userLanguage);
ControllerContext controllerContext = FakeControllerContextFactory.Create(request);
// Act
ViewEngineResult result = engine.FindPartialView(controllerContext, VIEW_NAME, false);
// Assert
RazorView razorView = (RazorView)result.View;
string actualViewPath = razorView.ViewPath;
actualViewPath.Should().Be(EXPECTED_VIEW_PATH);
}
P.S. I'm using xUnit as my testing framework and NSubstitute as my mocking framework should I install both AutoFixture.Xunit and AutoFixture.AutoNSubstitute?
UPDATE: After learning more and more about it I guess it is not the right tool for the job because I tried to replace my test doubles factories with AutoFixture rather than setting up my SUT with it.
Due to odd reason I thought it's doing the same thing NBuilder is doing and from what I can see they are very different tools.
So after some thinking I think I'll go and change the methods I have on my test doubles factories to objects then use AutoFixture to create my SUT and inject my test doubles to it.
Note: I don't have the source code for the CsEmbeddedRazorViewEngine type and all the other custom types.
Here is how it could be written with AutoFixture:
[Theory]
[InlineAutoWebData("en-US", "about", "~/MyAssemblyName/Views/Home/Index.cshtml")]
[InlineAutoWebData("en-US", "other", "~/MyAssemblyName/Views/Home/Index.cshtml")]
public void Should_return_the_default_path_of_the_view_for_enUS(
string language,
string viewName,
string expected,
ControllerContext controllerContext,
CsEmbeddedRazorViewEngine sut)
{
var result = sut.FindPartialView(controllerContext, viewName, false);
var actual = ((RazorView)result.View).ViewPath;
actual.Should().Be(expected);
}
How it works:
It uses AutoFixture itself together with it's glue libraries for xUnit.net and NSubstitute:
PM> Install-Package AutoFixture.Xunit
PM> Install-Package AutoFixture.AutoNSubstitute
With InlineAutoWebData you actually combine inline values and auto-generated data values by AutoFixture – also including Auto-Mocking with NSubstitute.
internal class InlineAutoWebDataAttribute : CompositeDataAttribute
{
internal InlineAutoWebDataAttribute(params object[] values)
: base(
new InlineDataAttribute(values),
new CompositeDataAttribute(
new AutoDataAttribute(
new Fixture().Customize(
new WebModelCustomization()))))
{
}
}
Remarks:
You could actually replace the WebModelCustomization customization above with AutoNSubstituteCustomization and it could work.
However, assuming that you are using ASP.NET MVC 4, you need to customize the Fixture instance with:
internal class WebModelCustomization : CompositeCustomization
{
internal WebModelCustomization()
: base(
new MvcCustomization(),
new AutoNSubstituteCustomization())
{
}
private class MvcCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customize<ControllerContext>(c => c
.Without(x => x.DisplayMode));
// Customize the CsEmbeddedRazorViewEngine type here.
}
}
}
Further reading:
Encapsulating AutoFixture Customizations
AutoData Theories with AutoFixture
I ended up doing this.
[Theory,
InlineData("en-US", "Index", "~/MyAssemblyName/Views/Home/Index.cshtml"),
InlineData("en-us", "Index", "~/MyAssemblyName/Views/Home/Index.cshtml"),
InlineData("en", "Index", "~/MyAssemblyName/Views/Home/Index.cshtml")]
public void Should_return_the_default_path_of_the_view(string language, string viewName, string expected)
{
// Arrange
CsEmbeddedRazorViewEngine engine = new CsEmbeddedRazorViewEngineFixture();
ControllerContext controllerContext = FakeControllerContextBuilder.WithLanguage(language).Build();
// Act
ViewEngineResult result = engine.FindPartialView(controllerContext, viewName, false);
// Assert
string actualViewPath = ((RazorView)result.View).ViewPath;
actualViewPath.Should().Be(expected);
}
I encapsulated the details to setup my SUT into a fixture and used the builder pattern to handle my fakes, I think that it's readable and pretty straightforward now.
While AutoFixture looks pretty cool, the learning curve seems long and I will need to invest enough time to understand it, for now, I want to clean-up my unit tests and make them more readable. :)
I get the exception:
1) More than one export was found that matches the constraint:
ContractName CompositionTest.C
RequiredTypeIdentity CompositionTest.C
When running the program
namespace CompositionTest
{
// [Export] // Also doesn't work
[Export(typeof(C))]
public class C
{
//[ImportAttribute(AllowRecomposition = true)] // also doesn't work
[Import(AllowRecomposition = true)]
public C PropertyC { get; set; }
}
class Program
{
static void Main(string[] args)
{
// Declare a composition container.
CompositionContainer compositionContainer = new CompositionContainer();
compositionContainer.ComposeParts( new C() );
compositionContainer.ComposeParts( new C() ); // exception here!
}
}
}
What am I doing wrong?
The first time you call ComposeParts, a new C object is added as an export to the container. Then second time you call ComposeParts, another C object is added as an export. This creates a problem with the import because there are two possible parts for import and MEF cannot make a decision. Hence the cardinality exception.
One solution would be to change the import to:
[ImportMany(AllowRecomposition = true)]
public IEnumerable<C> PropertyC { get; set; }
Another solution is to actually use a catalog when creating the container. This is the common way to use MEF. Pretty much all the examples you can find follow this approach:
//Create a catalog. In this case, a catalog based on an already loaded assembly.
var catalog = new AssemblyCatalog(typeof(C).Assembly);
//Create a container using the catalog. Only the parts from that catalog will be used.
var compositionContainer = new CompositionContainer(catalog);
For more on catalogs you should read this article.
By the way I have never seen such an example of MEF usage before. My answer is mainly based on observations I made while debugging it.
I have a silverlight 4 project with mvvmlight and ninject 3.x.
I've setup the container like this
kernel = new StandardKernel(new ViewModelModule(), new ClientSessionModule());
And the modules like this
public class ViewModelModule : NinjectModule
{
public override void Load()
{
((StandardKernel)Kernel)
.Bind(scanner => scanner.FromThisAssembly()
.Select(x => x.IsSubclassOf(typeof(ViewModelBase)))
.BindDefaultInterface());
}
}
and
public class ClientSessionModule : NinjectModule
{
public override void Load()
{
Kernel.Bind<IClientContext>().To<ClientContext>().InSingletonScope();
}
}
Now the problem is the latter one. At one point in the application this dependency is resolved explictly and updated like this:
var context = App.Ioc.Get<IClientContext>();
context.Username = "just a sample name";
Now when a ViewModel is loaded it get the IClientContext injected like
public MainViewModel(IClientContext clientContext)
The problem is that the instance does not have the name set earlier.
But if I inside the same ViewModel resolves explictly again I get the expected instance with the name set.
What am I missing since the sigleton does not get injected as I expected it to be automatically?
Just found a duplicate kernel in my solution. And that explains why I was not able so resolve as expected as I had 2 kernels running