4

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.

Blake Rivell
  • 13,105
  • 31
  • 115
  • 231
  • Why don't you use the [typed options framework](https://github.com/aspnet/Options) which is shipped with ASP.NET? This allows you to just inject an `IOptions`. – Henk Mollema Mar 11 '16 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. – Blake Rivell Mar 14 '16 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. – Blake Rivell Mar 14 '16 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. – Blake Rivell Mar 14 '16 at 14:38

1 Answers1

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

Community
  • 1
  • 1
Danny van der Kraan
  • 5,344
  • 6
  • 31
  • 41
  • I think we are on the right track, but can I get an example of incorporating fixtures and DI? – Blake Rivell Mar 11 '16 at 13:04
  • 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. – Blake Rivell Mar 14 '16 at 13:16
  • 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 Rivell Mar 14 '16 at 13:23
  • 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. – Danny van der Kraan Mar 14 '16 at 13:52
  • 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. – Blake Rivell Mar 14 '16 at 14:05
  • I updated my post one more time so you can see how things flow from my ASP.NET MVC app all the way to my repository. I just want to make sure we are on the same page. After seeing that do you still think I should be going in the direction of your answer? See how the CustomersController accesses the CustomerService? I need the test to accesses CustomerService. – Blake Rivell Mar 14 '16 at 14:14
  • Blake, ofcourse you don't have PrimeCheckerMiddleware. That is just a class from my sample. As far as the Autofac stuff, I forgot to put that in comment. Please do so. And I don't think you can use your Startup file, because of your particular use case. You will need to register the dependencies yourself in the TestServer. But I am having a problem right now with the sample project which i don't understand because it worked friday. It suddenly has a problem with AlternativePrimeCheckerOptions. So hold on please. – Danny van der Kraan Mar 14 '16 at 14:54
  • No big deal, I just want to make sure you see the update I made to my post because it will put us on the same page. I think everything is shaping up, I just need to figure out how to use the .NET dependency resolver in my fixture. I don't actually need to do Integration testing and call methods directly from my controller. I am doing Unit tests but with my repository layer. – Blake Rivell Mar 14 '16 at 14:55
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/106254/discussion-between-blake-rivell-and-danny-van-der-kraan). – Blake Rivell Mar 14 '16 at 15:06
  • hi @DannyvanderKraan do you think you can answer this question also? Thanks ! just sent points for this answer https://stackoverflow.com/questions/57331395/net-core-execute-all-dependency-injection-in-xunit-test-for-appservice-reposit?noredirect=1&lq=1 –  Aug 03 '19 at 03:39