5

I have an ASP.NET Core 1.0 Solution with the following project structure:

Web App (ASP.NET MVC6)
BusinessLibrary (Class Library Package)
DataLibrary(Class Library Package)
Tests (Class Library Package w/ XUnit)

I am attempting to use Microsoft's new built-in dependency injection all throughout the entire system.

Here is how everything currently flows from my ASP.NET MVC App all the way down to my Repository layer

//Startup.cs of MVC Web App
public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddMvc();

    services.AddSingleton(_=> Configuration);

    services.AddTransient<ICustomerService, CustomerService>();
    services.AddTransient<ICustomerRepository, CustomerRepository>();
}

public class CustomersController : Controller
{
    private ICustomerService _service;
    public CustomersController(ICustomerService service)
    {
        _service= service;
    }
}

public class CustomerService : ICustomerService
{
    private ICustomerRepository _repository;
    public PriceProtectionManager(ICustomerRepository repository)
    {
        _repository = repository;
    }
}

public class CustomerRepository : BaseRepository, ICustomerRepository
{
    public CustomerRepository(IConfigurationRoot config) 
    : base(config)
    {
    }
}

public class BaseRepository
{
    private IConfigurationRoot _config;

    public BaseRepository(IConfigurationRoot config)
    {
        _config = config;
    }
}

Now how can I get something similar to work with XUnit project so I can access CustomerService and call the functions?

Here is what my Fixture class looks like:

public class DatabaseFixture : IDisposable
{
    public ICustomerService CustomerService;
    public DatabaseFixture(ICustomerService service)
    {
        CustomerService = service;
    }

    public void Dispose()
    {

    }
}

The problem is that ICustomerService is unable to be resolved... This is probably because I don't have a Startup.cs like my WebApp. How do I replicate this behavior with the test project? I don't know where to create my TestServer because if I do it in the fixture it will be too late.

4
  • Why don't you use the typed options framework which is shipped with ASP.NET? This allows you to just inject an IOptions<T>. Commented Mar 11, 2016 at 10:33
  • @DannyvanderKraan please see my comment on your other posts. Additionally, see the update I made to my post of my current code. Commented Mar 14, 2016 at 13:37
  • @HenkMollema can you elaborate on this? And please see my updated post on how my MVC app currently drills down to the repository layer using DI. Commented Mar 14, 2016 at 14:21
  • @DannyvanderKraan Sorry to bother you again, but can you please see my edit to see how everything flows from my MVC web app down to the repository layer, and then what my current fixture class looks like. The fixture is basically equivalent to the Controller in my asp.net mvc app. Commented Mar 14, 2016 at 14:38

1 Answer 1

3

Well, you can provide your own dependencies to your SUT (which is the way you should want it IMHO). I've just answered a similar question here.

If you want to define your connectionstring at one place you could use xUnit's ability to use shared context (fixtures).

Update: Examples incorperating fixtures and DI...

Your testclass should implement IClassFixture and contain for example the following fields and constructor:

    public class AspnetCoreAndXUnitPrimeShould: IClassFixture<CompositionRootFixture>
{
    private readonly TestServer _server;
    private readonly HttpClient _client;
    private readonly CompositionRootFixture _fixture;

    public AspnetCoreAndXUnitPrimeShould(CompositionRootFixture fixture) 
    {
        // Arrange
        _fixture = fixture;
        _server = new TestServer(TestServer.CreateBuilder(null, app =>
        {
            app.UsePrimeCheckerMiddleware();
        },
            services =>
            {
                services.AddSingleton<IPrimeService, NegativePrimeService>();
                services.AddSingleton<IPrimeCheckerOptions>(_ => new AlternativePrimeCheckerOptions(_fixture.Path));
            }));
        _client = _server.CreateClient();
    }

Notice that AspnetCoreAndXUnitPrimeShould is the name of the testclass in my example. The fixture looks like:

    public class CompositionRootFixture
{
    public string Path { get; }

    public CompositionRootFixture()
    {
        Path = "@/checkprime";
    }
}

This is just a quick adoptation from another example, but you should understand how you can fix your problem now. AlternativePrimeCheckerOptions takes a string in the constructor, just like your Configuration class could. And with a fixture you arrange this connectionstring at one place.

Update Sample: https://github.com/DannyvanderKraan/ASPNETCoreAndXUnit

Sign up to request clarification or add additional context in comments.

10 Comments

I think we are on the right track, but can I get an example of incorporating fixtures and DI?
Danny thank you very much for this example. I don't know if you noticed, but I am the same person from the other post. Probably shouldn't have opened two. Is there any chance you can load an example on github that shows me: If I have 'IProductRepo' and 'ProductRepo' how I can access an instance of ProductRepo in my test class using DI? Before even posting in here I was trying to use a combination of Xunit Shared Context documentation and ASP.NET Core 1.0 Integration testing documentation. And still wasn't able to put together a working solution.
I would just simply do something like : private IProductRepo _productRepo= new ProductRepo(); at the top of my test class, but the trick is that my ProductRepo asks for IConfigurationRoot to be injected since I use that for my connectionstring.
Blake, yeah i noticed that later. The answer is indeed almost the same. First just add IConfigurationRoot to the services of the TestServer. Then have ProductRepo request an instance of IConfigruationRoot through its constructor and add it to the same services collection of the TestServer. And the underlying dependency injection container will handle the injection of the dependencies. As the fixture is concerned, I injected a 'path', you can inject a 'connectionstring' or whatever the same way. See update for sample.
I don't have UsePrimeCheckerMiddleware.. And in the CompositionRootFixture class intellisense is erroring on ContainerBuilder, RegisterInstance, and Resolve. Are these AutoFac? Because I am not using AutoFac. And shouldn't I be passing the TestServer a Startup.cs file coming from my Tests project like in my example above? I just don't understand how DI works so smoothly from the ASP.NET app all the way through to my repository and making it flow from my Unit Test to the repository is so much different.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.