I am using a subclass of ConfigurableBootstrapper to test my Nancy modules. This is a workaround to get the ConfigurableBootstrapper to pick up the custom view location convention I use in the 'real' bootstrapper:
public class ConfigurableBootstrapperWithCustomConvention : ConfigurableBootstrapper
{
public ConfigurableBootstrapperWithCustomConvention(Action<ConfigurableBootstrapperConfigurator> configuration)
: base(configuration)
{
}
protected override void ConfigureConventions(NancyConventions nancyConventions)
{
nancyConventions.ViewLocationConventions.Add((viewName, model, context) =>
string.Concat(context.ModuleName, "/Views/", viewName));
base.ConfigureConventions(nancyConventions);
}
}
In my tests I first set the root path to that of my nancy project using the FakeRootPathProvider. This contains the necessary folder structure ("/Home/Views/Index.cshtml") for the view used in HomeModule to be located using this custom convention. The (simplified) test code:
[Test]
public void when_the_default_page_is_loaded_it_should_show_links_to_submit_form()
{
FakeRootPathProvider.RootPath = "../../../MyApp.Web";
var bootstrapper = new ConfigurableBootstrapperWithCustomConvention(with =>
{
with.RootPathProvider(new FakeRootPathProvider());
with.ViewEngine<RazorViewEngine>();
with.Module<HomeModule>();
});
var browser = new Browser(bootstrapper);
var response = browser.Get("/");
Assert.That(response.Body.AsString(), Is.StringContaining("<a href=\"SubmitSelf\">"));
}
When I run this test I get the following exception (at the call to response.Body):
System.ArgumentNullException : Value cannot be null.
Parameter name: httpContext
at System.Web.HttpContextWrapper..ctor(HttpContext httpContext)
at System.Web.Optimization.Styles.RenderFormat(String tagFormat, String[] paths)
at RazorOutput.RazorView.Execute()
at Nancy.ViewEngines.Razor.NancyRazorViewBase`1.ExecuteView(String body, IDictionary`2 sectionContents)
at System.Dynamic.UpdateDelegates.UpdateAndExecuteVoid3<T0,T1,T2>(CallSite site, T0 arg0, T1 arg1, T2 arg2)
at Nancy.ViewEngines.Razor.RazorViewEngine.<>c__DisplayClass27.<RenderView>b__26(Stream stream)
at Nancy.Testing.BrowserResponse.get_Body()
at MyApp.Tests.Integration.Web.Home.HomeModuleTests.when_the_default_page_is_loaded_it_should_show_links_to_submit_form() in HomeModuleTests.cs: line 44
If I set the Fake root path to be "../../../MyApp.Web/Home/Views" instead, the test runs OK. (It appears that the custom view location convention is being ignored when testing using Nancy's "Browser" class).
Is there some issue with setting a NancyConvention in this way?
If so is there a different way to set a view location convention with ConfigurableBootstrapper?
Related
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.
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
i have a solution combined with several projects.
this is my App.xaml.cs
public partial class App : Application
{
private SiteManager _siteManager = new SiteManager();
public SiteManager SiteManager
{
get { return _siteManager; }
set { _siteManager = value; }
}
}
during my run i call another project in the same solution
SiteDll.MainWindow siteManagerDialog = new SiteDll.MainWindow();
siteManagerDialog.Show();
but i dont know how to pass all vars in App.xaml.cs to SiteDll.MainWindow siteManagerDialog.
i tried:
SiteDll.MainWindow siteManagerDialog = new SiteDll.MainWindow((App)Application.Current);
siteManagerDialog.Show();
and cast it in SiteDll.MainWindow constructor:
public MainWindow(object me)
{
Application app = ((App)me);
InitializeComponent();
}
but i get casting error...
what is the correct way to do it ?
You are casting YourApplication1.App type to YourApplication2.App which are different types. That's why you get a invalid cast exception.
What you can do is, you can put your common variables in a separate assembly and reference this assembly from both of your applications.
Edit
I would also suggest you to add a 'WPF User Control Library' and then reference it when you are using wpf windows/pages/user controls from other assemblies, to prevent such confusions.
I have a class that uses a lot of database internally, so I built the constructor with a $db handle that I am supposed to pass to it.
I am just getting started with PHPUnit, and I am not sure how I should go ahead and pass the database handle through setup.
// Test code
public function setUp(/*do I pass a database handle through here, using a reference? aka &$db*/){
$this->_acl = new acl;
}
// Construct from acl class
public function __construct(Zend_Db_Adapter_Abstract $db, $config = array()){
You would do it like this:
public class TestMyACL extends PHPUnit_Framework_TestCase {
protected $adapter;
protected $config;
protected $myACL;
protected function setUp() {
$this->adapter = // however you create a new ZendDbADapter
$this->config = // however you create a new config array
$this->myACL = new ACL($this->adapter, $this->config); // This is the System Under Test (SUT)
}
}
IMHO, you need to work on your naming conventions. See Zend Framework Naming Conventions, for a start. An example would be the underscore, look up variables in the link. Also class naming.
You can do normally without reference same as constructor because this method is simplest.
I have a Silverlight application which has two different XAPs - an InitialXAP which is loaded statically by the HTML page and a DynamicXAP which is loaded from code within the initial XAP. The DynamicXAP is loaded with code similar to this:
var asm = LoadAssemblyFromXap(stream, "DLLName");
// LoadAssemblyFromXAP will load the DynamicXAP as a file stream,
// unpack it and load DLLName as a dll.
var controllerType = asm.GetType("ClassNameToInstantiate_InsideAsm");
var constructor = controllerType.GetConstructor(Type.EmptyTypes);
return constructor.Invoke(null);
I have a class which uses reflection (specifically FieldInfo.GetValue) to do data binding. This class is defined in the InitialXAP. If I try to use this class in the DynamicXAP, I get an error:
Message: Unhandled Error in Silverlight Application System.FieldAccessException: Class.In.DynamicXAP.Which.Uses.The.Reflection.Class.In.InitialXAP
at System.Reflection.RtFieldInfo.PerformVisibilityCheckOnField(IntPtr field, Object target, IntPtr declaringType, FieldAttributes attr, UInt32 invocationFlags)
at System.Reflection.RtFieldInfo.InternalGetValue(Object obj, Boolean doVisibilityCheck, Boolean doCheckConsistency)
at System.Reflection.RtFieldInfo.InternalGetValue(Object obj, Boolean doVisibilityCheck)
at System.Reflection.RtFieldInfo.GetValue(Object obj)
I can get around this error by creating a subclass of the class using reflection and overriding the method using reflection like so:
public class InitialXAP.ClassUsingReflection {
public virtual object GetValue()
{
return fieldInfo.GetValue(parent);
}
}
public class ClassUsingReflection : InitialXAP.ClassUsingReflection {
public override object GetValue()
{
return fieldInfo.GetValue(parent);
}
}
But I would prefer to avoid this duplication by allowing reflection from the InitialXAP in the DynamicXAP. Any ideas on what I can do?
Although there is a learning curve, I would look at Silverlight MEF or Prism (both are together at last in the latest Prism 4 Beta). They both support dynamic loading of modules and enforce good patterns for reuse and separate/team development.
InitialXAP.ClassUsingReflection...
Note the duplicate isn't part of the inital xap namespace (ClassUsingReflection), and may be imported.
Notice GetVisible - as in not visible to Dynamic xap...
Just leave the duplicate (take away base class obviously) and try.