3
\$\begingroup\$

Here's what I got:

[TestFixture]
public class CompositionRootTests {
    [Test]
    public void FormsShouldBeBoundToViewsThroughConventionBinding() {
        GivenIHaveANewKernel();
        WhenBindingFormsToViews();

        // Then
        kernel.Get<IMainView>().Should().BeOfType<MainForm>();
    }

    [Test]
    public void InterfacesEndingWithTheWordFactoryShouldBeBoundAsFactoriesThroughConvetionBinding() {
        GivenIHaveANewKernel();
        WhenBindingFactories();

        // Then
        kernel.Should()
            .Resolve<ICustomerManagementPresenterFactory>()
            .WithSingleInstance();
    }

    private void GivenIHaveANewKernel() { kernel = new StandardKernel(); }

    private void WhenBindingFactories() {
        kernel.Bind(services => services
            .From(AppDomain.CurrentDomain
                .GetAssemblies()
                .Where(assembly => assembly.FullName.Contains("MyProject")
                                && !assembly.FullName.Contains("Test")))
            .SelectAllInterfaces()
            .EndingWith("Factory")
            .BindToFactory());
    }

    private void WhenBindingFormsToViews() {
        kernel.Bind(services => services
            .From(AppDomain.CurrentDomain
                .GetAssemblies()
                .Where(assembly => assembly.FullName.Contains("MyProject")
                                && !aasembly.FullName.Contains("Tests")))
            .SelectAllClasses()
            .EndingWith("Form")
            .BindSelection((type, baseType) => type
                .GetInterfaces()
                .Where(iface => iface.Name.EndsWith("View"))));
    }

    private IKernel kernel;
}

I'd like to write a parametirized Then method where I could pass the type to be resolved, and the type to which it should be bound.

ThenIShouldResolve<IMainView, MainForm>();

But I wonder whether it is really cleaner than what I actually got with my // Then comment. In fact, the Given... and the When... helper methods were comments such as // Given and // When. Then, when I bound my presenters to themselves, I encountered a scenario where those depend on the prior bindings because of my design.

public class MainPresenter : Presenter<IMainView>, IMainViewUiHandler {
    public MainPresenter(IMainView view, ICustomerManagementPresenterFactory factory)
        : base(view) {
        view.Handler = this;
        customerManagementPresenterFactory = factory;
    }

    private readonly ICustomerManagementPresenterFactory customerManagementPresenterFactory;
}

Hence the required prior bindings to the factories and the views in order to bind the presenters, which I feel comfortable with. And because of this requirement, I decided to refactor my code to helper methods with names inpired from BDD.

Because of the way it is written using fluent syntax, I feel like my When methods aren't clean enough, or my code looks sloppy.

Perhaps could I refactor my When... methods to reuse the binding and parameterize the convention instead?

private void WhenBindingClassesUsingConvention(string classesEndingWith, string interfacesEndingWith) {
    kernel.Bind(services => services
        .From(AppDomain.CurrentDomain
            .GetAssemblies()
             .Where(assembly => assembly.FullName.Contains("MyProject")
                             && !assembly.FullName.Contains("Tests")))
        .SelectAllClasses()
        .EndingWith(classesEndingWith)
        .BindSelection((type, baseType) => type
            .GetInterfaces()
            .Where(iface => iface.Name.EndsWith(interfacesEndingWith));
}

private void WhenBindingFactoriesUsingConvention(string interfacesEndingWith) {
    kernel.Bind(services => services
        .From(AppDomain.CurrentDomain
            .GetAssemblies()
             .Where(assembly => assembly.FullName.Contains("MyProject")
                             && !assembly.FullName.Contains("Tests")))
        .SelectAllInterfaces()
        .EndingWith(interfacesEndingWith)
        .BindToFactory());
}

Is it overkill or something, I wonder? One way or another, I can't really compress this code anymore, I guess. Perhaps is it cleaner to use parameterized When... methods?

\$\endgroup\$
  • \$\begingroup\$ Please revise the title to state the purpose of the code only. \$\endgroup\$ – Jamal Oct 29 '14 at 14:08
6
\$\begingroup\$

Regarding your fluent approach to assertions, I'm definitely a fan of anything that makes tests more succinct and readable - as long as it's crystal clear what's going on. A one-liner like "kernel = new StandardKernel()" seems more readable than "GivenIHaveANewKernel()" to me.

As a rule of thumb the tests should be very simple without having to resort to a whole lot of syntactic gymnastics. If the tests are complicated and in need of refactoring it's often an indication that the code under test could use some refactoring itself.

Honestly a bigger issue here is what this fixture is actually testing. I would ask yourself the questions "what am I trying to test", and "do I really need to test it". In this case it appears that you are trying to test Ninject functionality rather than your own code. Time might be better off spent testing other things.

\$\endgroup\$
  • \$\begingroup\$ +1 For your critical point of view, I appreciate it. Besides, I'm not much testing Ninject as much as I do test my understanding and my CompositionRoot so that I am sure that I use Ninject correctly, and that my methods work as expected once used within my program. I'd like to hear further from you. =) \$\endgroup\$ – Will Marcouiller Sep 29 '14 at 16:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.