Dependency Injection in Asp.net core Integration testing - testing

I successfully injected dependencies using Moq in my unit test project. But for the integration testI would like to interact with the database. So I canot fake the repositories/ dependencies. I am having trouble how to achieve such thing in seperate class library introduced for integration testing.
I would like to do something like this (data should come from database):
public class CountryServiceIntegrationTest
{
private ICountryService countryService;
public CountryServiceIntegrationTest(ICountryService _countryService)
{
countryService = _countryService;
}
#endregion
[Fact]
public void Should_Return_ListOf_Countries()
{
//Act
var myList = countryService.GetList("A");
//Assert
Assert.True(myList.Count > 0);
}
}
My CountryService Class:
public class CountryService : ICountryService
{
// Note: Have to use Core.Domain.Country because of the namespace has Quantum.Service.Country
protected IRepository<Core.Domain.Country> _countryRepository;
protected IRepository<Core.Domain.State> _stateRepository;
protected IRepository<Core.Domain.City> _cityRepository;
public CountryService(IRepository<Core.Domain.Country> countryRepository, IRepository<Core.Domain.State> stateRepository, IRepository<Core.Domain.City> cityRepository)
{
_countryRepository = countryRepository;
_stateRepository = stateRepository;
_cityRepository = cityRepository;
}
public IList<CountryViewModel> GetList(string name)
{
var query = _countryRepository.Table.AsQueryable();
if (string.IsNullOrEmpty(name) == false)
{
query = query.Where(i => i.CountryName.StartsWith(name));
}
return query.Select(i => new CountryViewModel()
{
CountryCode = i.CountryCode,
CountryName = i.CountryName,
Currency = i.Currency,
CurrencyName = i.CurrencyName,
CurrencySymbol = i.CurrencySymbol,
TelephoneCountryCode = i.TelephoneCountryCode,
UnitOfMeasure = i.UnitOfMeasure
}).ToList();
} }
Well I have separate IOC class library project where dependencies are registered. This is then registered in the Startup.cs class. Since Startup.cs class isn't invoked during the tests, the dependencies aren't injected. So how can I solve this problem?
------UPDATED As per guidelines found in official documentation here -----
Well now:
I followed this link and did as per it. It seems to me that Startup class was called which also calls the ConfigureDependency.RegisterDependencies(..).
Test Class:
public CountryServiceIntegrationTest()
{
_server = new TestServer(new WebHostBuilder()
.UseStartup<Startup>());
_client = _server.CreateClient();
}
[Fact]
public async Task ReturnHelloWorld()
{
//Act
var response = await _client.GetAsync("/home/Test");
response.EnsureSuccessStatusCode();
var responseString = await response.Content.ReadAsStringAsync();
//Assert
Assert.Equal("test", responseString);
}
Startup.ConfigureServices() :
public IConfigurationRoot Configuration { get; }
//gets called in the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
//services.AddSingleton<ILogUserActivityService, LogUserActivityService>();
services.AddSingleton<ActivityLog>();
// Add framework services.
services.AddMvc();
// Register Database Connection String
var connectionSetting = new ConnectionSetting(Configuration["Data:ConnectionStrings:DefaultConnection"]);
services.AddSingleton<IConnectionSetting>(connectionSetting);
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
// Fill other dependencies
var configureDependency = new ConfigureDependency();
configureDependency.RegisterDependencies(services, connectionSetting);
}
ConfigureDependency.RegisterDependency(..):
public class ConfigureDependency
{
public IDatabaseFactory DatabaseFactory { get; set; }
public void RegisterDependencies(IServiceCollection services, IConnectionSetting connectionSetting)
{
services.AddDbContext<QuantumDbContext>(options => options.UseSqlServer(connectionSetting.Get()));
services.AddTransient<IDatabaseFactory, DatabaseFactory>();
services.AddTransient<IDbContext, TestDbContext>();
services.AddTransient<IDbContext, QuantumDbContext>();
..................................................................
...........service n repositories are registered here..............
}
}
But now what happens is I get this error:
Since Startup.cs is invoked which then calls the ConfigureDependency class, doesn't it mean that parameters(services, connectionSetting) shall be passed automatically. This is (ConfigureDependency.RegisterDependencies(..)) where I am getting an error.

It's an ArgumentNullException in the useSqlServer method:
It seems that connectionSetting.Get() returns null.
In the following code
var connectionSetting = new ConnectionSetting(Configuration["Data:ConnectionStrings:DefaultConnection"]);
services.AddSingleton<IConnectionSetting>(connectionSetting);
It suggests that ConnectionSetting implements the interface IConnectionSetting
so why didn't you use directly the instance instead of calling Get() on it ?
Like below:
services.AddDbContext<QuantumDbContext>(options => options.UseSqlServer(connectionSetting))
Additional Remarks:
It really depends on what you do mean by integration test. It could refers to:
higher level unit tests (as opposed to unit tests limited to one class, such integration tests will test integration between different classes).
namespace level integration tests (test one or several public interfaces from a given namespace without checking inner classes).
assembly level integration tests (same as namespace but with an assembly scope).
black box integration tests (test the full software on its interactions fr om the external systems point-of-view). The ASP.NET integration testing documentation is related to this kind of test.
It's often better to have several layers test-covered before trying to do the Big Bang testing... but it's a matter of tradeoff between time and quality.
In order to make the not so high level integration tests possible/easy to write:
You should not share the same database environment between your tests and your production code (so not the same connection string).
you shouldn't use Startup as it's designed to mimics the whole website on a test server.
Registration and Resolution of services should be splitted up in some coherent specific classes to make integration tests on specific parts easier.

Related

Why WebApplicationFactory is saving state from previous builds?

I will try to show my problem with a sample code easier to understand.
I have used WebApplicationFactory to develop my acceptance tests. Let's say that I have the typical minimal Program.cs with the following line to register one of my modules:
builder.Services.RegisterModule<StartupRegistrationModule>(builder.Configuration, builder.Environment);
And this module is declared like this:
internal sealed class StartupRegistrationModule : IServiceRegistrationModule
{
public static Dictionary<string, string> _dictionary = new();
public void Register(IServiceCollection services, IConfiguration configuration, IHostEnvironment hostEnvironment)
{
// Lot of modules being registered
_dictionary.Add("key", "value");
}
}
One of my tests file is like this:
public sealed class MyTests : AcceptanceTestBase
{
[Fact]
public void Test1()
{
// arrange
// act
// assert
}
[Fact]
public void Test2()
{
// arrange
// act
// assert
}
[Fact]
public void Test3()
{
// arrange
// act
// assert
}
}
And AcceptanceTestBase is:
public abstract class AcceptanceTestBase : IDisposable
{
protected HttpClient _httpClient;
protected WebApplicationFactory<Program> _webApplicationFactory;
public AcceptanceTestBase()
{
_webApplicationFactory = new WebApplicationFactory<Program>()
.WithWebHostBuilder(builder =>
{
// ... Configure test services
});
_httpClient = _webApplicationFactory.CreateClient();
}
public void Dispose()
{
_httpClient.Dispose();
_webApplicationFactory.Dispose();
}
}
If I try to execute all these tests my tests will fail in the second test run because the WebApplicationFactory is trying to build again the Application but it already has the key in the dictionary and it will fail. See the image for more understanding on the problem.
So my question is, how can I build the application in different scopes to do not share this dictionary state?
Thanks :)
Update:
The real static dictionary is saved behind this nuget package that keeps the track of all my circuit breaker policies state. I do not actually need even the HttpClients for my tests but did not find a way to remove them and not load this. I tried removing all the HttpClients to see if it also removes their dependencies, but it does not seem to make the trick.
It is because you are using:
internal sealed class StartupRegistrationModule : IServiceRegistrationModule
{
/// .. static here
public static Dictionary<string, string> _dictionary = new();
public void Register(IServiceCollection services, IConfiguration configuration, IHostEnvironment hostEnvironment)
{
// Lot of modules being registered
_dictionary.Add("key", "value");
}
}
The static Dictionary is shared over all your tests because they run in the same process.
Each test starts a new (Test-)WebHost but the dictionary remains untouched.
My proposal is to not use statics anywhere in DI context to prevent such hidden traps.
I don't know the purpose of your Dictionary here but maybe you can extract this to a singleton registration which you can replace in your (Test.)WebHost on each new test / startup?

XUnit Test Constructor dependence injection with Autofac

I am implementing Xunit with Autofac, I could make it work by below code:
using (var scoped = DbFixture.Container.Resolve<UserReponsitory>())
{
var result = (scoped.GetAll()).ToList().Count();
Assert.Equal(2, result);
}
But I want to inject UserReponsitory to test method instead of using DbFixture.Container.Resolve. Is it possible to make below code work?
UnitTest1.cs
namespace XUnitTestPro
{
public class UnitTest1:IClassFixture<DbFixture>
{
private IUserReponsitory _userReponsitory;
public UnitTest1(IUserReponsitory userReponsitory)
{
_userReponsitory = userReponsitory;
}
[Fact]
public void Test1()
{
//using (var scoped = DbFixture.Container.Resolve<UserReponsitory>())
//{
// var result = (scoped.GetAll()).ToList().Count();
// Assert.Equal(2, result);
//}
var result = _userReponsitory.GetAll().ToList().Count();
Assert.Equal(2, result);
}
}
}
DbFixture.cs
namespace XUnitTestPro
{
public class DbFixture
{
public static IContainer Container { get; set; }
public DbFixture()
{
var builder = new ContainerBuilder();
var option = new DbContextOptionsBuilder<UserContext>().UseSqlServer("Server=(localdb)\\MSSQLLocalDB;Database=EFProject;Trusted_Connection=True;MultipleActiveResultSets=true").Options;
UserContext context = new UserContext(option);
builder.RegisterInstance(context).As<UserContext>();
builder.RegisterType<UserReponsitory>().AsSelf().As<IUserReponsitory>();
builder.RegisterAssemblyTypes(typeof(DbFixture).GetTypeInfo().Assembly);
Container = builder.Build();
}
}
}
At present, I got below error, it seems to be related with IClassFixture<DbFixture> and public UnitTest1(IUserReponsitory userReponsitory) are different.
Message: The following constructor parameters did not have matching
fixture data: IUserReponsitory userReponsitory
Is there any way to achieve below code without call DbFixture.Container.Resolve which is similar to inject MVC Controller?
public UnitTest1(IUserReponsitory userReponsitory)
{
_userReponsitory = userReponsitory;
}
In other words, how could I dependence inject Unit Test class?
Any help would be appreciated.
Dependency Injection support in xUnit is kinda limited.
When you implement IClassFixture<DbFixture> interface, then xUnit expects one DbFixture parameter in it's constructor, and the type of the parameter depends on T in IClassFixture<T>.
That being said, when you implmenent IClassFixture<DbFixture> your constructor must look like public UnitTest1(DbFixture). But you have IUserRepository, so xUnit doesn't know what to inject in there.
You can also implement multiple IClassFixture<T> types, but you can use each T only once per test class.
From the official xUnit docs on shared context (IClassFixture<T>):
Important note: xUnit.net uses the presence of the interface IClassFixture<> to know that you want a class fixture to be created and cleaned up. It will do this whether you take the instance of the class as a constructor argument or not. Simiarly, if you add the constructor argument but forget to add the interface, xUnit.net will let you know that it does not know how to satisfy the constructor argument.
Update
It's still possible to use the IoC container resolve it, just not with constructor injection.
public class DbFixture
{
public IContainer Container { get; private set; }
public DbFixture()
{
var builder = new ContainerBuilder();
var option = new DbContextOptionsBuilder<UserContext>().UseSqlServer("Server=(localdb)\\MSSQLLocalDB;Database=EFProject;Trusted_Connection=True;MultipleActiveResultSets=true").Options;
UserContext context = new UserContext(option);
builder.RegisterInstance(context).As<UserContext>();
builder.RegisterType<UserReponsitory>().AsSelf().As<IUserReponsitory>();
builder.RegisterAssemblyTypes(typeof(DbFixture).GetTypeInfo().Assembly);
Container = builder.Build();
}
}
public class UnitTest1:IClassFixture<DbFixture>
{
private IUserReponsitory _userReponsitory;
public UnitTest1(DbFixture fixture)
{
// resolve it here
_userReponsitory = fixture.Container.Resolve<IUserRepository>();
}
[Fact]
public void Test1()
{
//using (var scoped = DbFixture.Container.Resolve<UserReponsitory>())
//{
// var result = (scoped.GetAll()).ToList().Count();
// Assert.Equal(2, result);
//}
var result = _userReponsitory.GetAll().ToList().Count();
Assert.Equal(2, result);
}
}
However, the question is rather is that good way to use it? Not sure what you want to reach, but if you want do unit tests, then you don't have to use IoC container at all or concrete classes, just mocks and the type you are testing.
If you want do integration tests on ASP.NET Core MVC / WebApi, then you should rather use TestServer class which spins up the whole application with all IoC you have configured there already.
If you already have constructor injection enabled in your unit tests, you are nearly done. In the constructor of your test, inject a
Func<Owned<UserReponsitory>>
e.g.
namespace XUnitTestPro
{
public class UnitTest1:IClassFixture<DbFixture>
{
private Func<Owned<UserReponsitory>> _userRepositoryFactory;
public UnitTest1(Func<Owned<UserReponsitory>> userRepositoryFactory )
{
_userReponsitoryFactory = userReponsitoryFactory;
}
[Fact]
public void Test1()
{
//using (var scoped = DbFixture.Container.Resolve<UserReponsitory>())
//{
// var result = (scoped.GetAll()).ToList().Count();
// Assert.Equal(2, result);
//}
using (var scoped = userReponsitoryFactory())
{
var result = (scoped.Value.GetAll()).ToList().Count();
Assert.Equal(2, result);
}
}
}
}
The Func is a factory that allows you to return a Owned. Owned is a container that allows you to dispose your object on your own (the using block)

Bootstrapping TestServer with TestStartup with InMemoryDatabase fails (.Net core)

Perhaps I've missed something, or perhaps something is broken. I hope to find out what happens here.
TLDR: Bootstrapping a TestServer class with an InMemory database, gives
(No service for type 'Microsoft.Data.Entity.Storage.IRelationalConnection' has been registered). Any clues? More details below:
I have a test class, which uses a TestFixture to bootstrap:
public AccountControllerTest(TestServerFixture testServerFixture) : base(testServerFixture)
{
}
The testServerFixture looks like this:
public class TestServerFixture : IDisposable
{
public TestServer server { get; }
public HttpClient client { get; }
public TestServerFixture()
{
// Arrange
var builder = TestServer.CreateBuilder()
.UseEnvironment("Development")
.UseStartup<TestPortalStartup>()
.UseServices(services =>
{
// Change the application environment to the mvc project
var env = new TestApplicationEnvironment();
env.ApplicationBasePath =
Path.GetFullPath(Path.Combine(PlatformServices.Default.Application.ApplicationBasePath, "..", "MY_APP"));
env.ApplicationName = "MY_APP";
//SUPER IMPORTANT: Should be the real application name, else you'll get Roslyn Compiler Errors in your views
services.AddInstance<IApplicationEnvironment>(env);
});
server = new TestServer(builder);
client = server.CreateClient();
}
public void Dispose()
{
server.Dispose();
client.Dispose();
}
}
And as you can see it uses a TestPortalStartup which looks like this:
public class TestPortalStartup : Startup
{
private Mock accountRegistrationClientMock;
public TestPortalStartup(IHostingEnvironment env, IApplicationEnvironment appEnv) : base(env, appEnv)
{
}
public override void SetUpDataBaseAndMigrations(IServiceCollection services)
{
services
.AddEntityFramework()
.AddInMemoryDatabase()
.AddDbContext<CmsDbContext> (
options => options.UseInMemoryDatabase()
);
}
public override void AddFrameworkDependencies(IServiceCollection services)
{
// ... not relevant
}
}
As you can see in the SetUpDataBaseAndMigrations we bootstrap an InMemoryDatabase and a DbContext.
I have used this construct before to test a Service that deals with the Database. (but this is isolated).
Now with an integration test I end up failing to bootstrap the test with:
Result StackTrace: at
Microsoft.Extensions.DependencyInjection.ServiceProviderExtensions.GetRequiredService(IServiceProvider
provider, Type serviceType) at
Microsoft.Extensions.DependencyInjection.ServiceProviderExtensions.GetRequiredService[T](IServiceProvider
provider) at
Microsoft.Data.Entity.Infrastructure.AccessorExtensions.GetService[TService](IInfrastructure`1
accessor) at
Microsoft.Data.Entity.RelationalDatabaseFacadeExtensions.GetRelationalConnection(DatabaseFacade
databaseFacade) at
Microsoft.Data.Entity.RelationalDatabaseFacadeExtensions.GetDbConnection(DatabaseFacade
databaseFacade) at
MY_APP.Portal.Startup.Configure(IApplicationBuilder app,
IHostingEnvironment env, ILoggerFactory loggerFactory) in
MY_APP/Startup.cs:line 175 Result Message: One or more errors
occurred. No service for type
'Microsoft.Data.Entity.Storage.IRelationalConnection' has been
registered. The following constructor parameters did not have matching
fixture data: TestServerFixture testServerFixture
In case you wonder what happens at MY_APP/Startup.cs (line 175) that is:
logger.LogInformation($"Using SQL Connection: {dbContext.Database.GetDbConnection().DataSource}");
Running with a 'normal' database (ie, not an In memory one) will PASS the test.
So it looks like some dependencies/wiring is missing? Anyone has experience with this? Clues? etc.
After I posted this question at the AspDotNet github, the answer was that the InMemoryDatabase from EntityFramework itself is not meant to do integration testing like this.
An alternative is using SQLite - but then also in memory mode.
Since creating all this (from scratch to fully working integration tests) took me quite some time to figure out. I figured I would summerise this all in a blog post:
http://www.stefanhendriks.com/2016/04/29/integration-testing-your-dot-net-core-app-with-an-in-memory-database/

MVC4 unit test and windows authentication

As far as I see, unless my mvc4 app uses windows authentication (and so my controllers tries to read the User objects) when I create my controller instance from a TestMethod, the User object remains null. So my tests fails. What can I do to get them work?
Additional informations:
This is my test:
[TestMethod]
public void Create()
{
var ctrl = new LanguageController();
var res = ctrl.Manage() as ViewResult;
Assert.IsNotNull(res);
Assert.AreEqual(res.ViewName, "Create");
}
And my LanguageController has a base class:
public class LanguageController : MyController
{
Which has a constructor, inside it I try to discover the user rights by an external Right Manager.
public class MyController : Controller
{
protected Rights rm;
public MyController()
{
this.rm = RightManager.Discover(User.Identity);
}
Here in this constructor I see the User is null.
Okay, there are few issues with your Unit test and I will go through them as I explain why the User is null.
It is simply because you haven't provide a stubbed version of the User (IPrincipal) instance. So you need to find a way to inject that into your Controller. It is important you externalize as much dependencies in your Controller so it provides not a clean Controller to work with but also and importantly promote the testability.
What I would do inject the dependencies as below.
Your SUT (System Under Test)
public class MyController : Controller
{
protected Rights rm;
public MyController(IPrincipal user, IRightManager rightManager)
{
this.rm = rightManager.Discover(user.Identity);
}
}
public class LanguageController : MyController
{
public LanguageController(IPrincipal user, IRightManager rightManager)
: base(user, rightManager)
{
}
public ActionResult Manage()
{
return View("Manage");
}
}
This gives me the ability to inject a fake User and also a fake Right Manager.
So how would you get the real User, RightManager when you run the application at runtime?
You can inject the dependencies to the Controller during the Controller creation.
If you don't use a dependency injection framework (Ideally you should), you can still inject dependencies in a manual way. For example, creating property in your Controller and inject the real instance in the Controller, and during the Unit Testing time inject the fake instance etc. I won't go into detail as I'm deviating a bit - but you can find lot SO questions/web references in regards to this aspect.
Your Unit test
Now you have a way to inject your dependencies you can easily inject them from your Unit test. You can either using an Isolation framework (AKA and Mock object framework) or you can inject them as the old school way - which is the Hand written mocks/fakes/stubs. I suggest using an Isolation framework. Creating manual fakes, introduces unnecessary code duplication and maintenance issue. Since I don't know which framework you prefer, I created few handwritten fakes/mocks/stubs.
public class FakeRightManager : IRightManager {
public Rights Discover(IIdentity identity) {
return new Rights();
}
}
public class MyFakeIdentity : IIdentity {
public string AuthenticationType {
get { throw new NotImplementedException(); }
}
public bool IsAuthenticated {
get { throw new NotImplementedException(); }
}
public string Name {
get { throw new NotImplementedException(); }
}
}
public class MyFakePrincipal : IPrincipal {
public IIdentity Identity {
get { return new MyFakeIdentity(); }
}
public bool IsInRole(string role) {
throw new NotImplementedException();
}
}
You Unit Test :
[TestMethod]
public void ManageAction_Execute_ReturnsViewNameManager()
{
var fakeUser = new MyFakePrincipal();
var fakeRightManager = new FakeRightManager();
var ctrl = new LanguageController(fakeUser, fakeRightManager);
var res = ctrl.Manage() as ViewResult;
Assert.AreEqual<string>(res.ViewName, "Manage");
}
In your test you check for Assert.IsNotNull(res); this not necessary as if the res is null your second assert going to fail anyway.
Also always give a very descriptive precise Unit Test name. Reflect what you exactly testing. It improves the test readability and maintainability.

Entity Framework 5 - How to change connection string for unit testing?

This is my first foray into Entity Framework, and I have a working project with EF5 and the repository pattern. I want to do integration testing against a live DB. I made a snapshot of my existing production database and wrote a stored procedure to recreate a fresh snapshot every time I want to run tests. My question is how to I switch my context to this database snapshot when "in unit testing mode"? In my app.config I have both my live and test connection strings as such:
<connectionStrings>
<add name="ReportingDbContext" connectionString="Server=LiveServer;Database=UnifiedReporting;User Id='myuser';Password='mypass';Trusted_Connection=False" providerName="System.Data.SqlClient" />
<add name="TestingDbContext" connectionString="Server=LiveServer;Database=UnifiedReportingSnapshot;User Id='myuser';Password='mypass';Trusted_Connection=False" providerName="System.Data.SqlClient" />
</connectionStrings>
As it stands now, I have my DbContext with the entities I want to use as follows:
public class ReportingDbContext : DbContext
{
public ReportingDbContext() : base("name=ReportingDbContext") // as per my app.config
{
}
// inventory
public DbSet<ComputerEntity> Computers { get; set; }
public DbSet<NetworkAdapterEntity> NetworkAdapters { get; set; }
// ... plus a whole bunch more
}
What I think I need to do is change the base("name=ReportingDbContext") into ("name=TestingDbContext"), but given how I have my Repository/UnitOfWork setup I'm not seeing how I can do so. The issue may be here in my UnitOfWork:
public interface IUnitOfWork : IDisposable
{
void Commit();
// inventory
IRepository<ComputerEntity> Computers { get; }
IRepository<NetworkAdapterEntity> NetworkAdapters { get; }
// ... plus a bunch more
}
public class UnitOfWork : IUnitOfWork
{
private readonly ReportingDbContext _dbContext = null;
public UnitOfWork()
{
_dbContext = new ReportingDbContext();
}
public void Commit()
{
_dbContext.SaveChanges();
}
// Inventory
public IRepository<ComputerEntity> Computers {get { return new Repository<ComputerEntity>(_dbContext); }}
public IRepository<NetworkAdapterEntity> NetworkAdapters { get { return new Repository<NetworkAdapterEntity>(_dbContext); } }
// ... lots more
}
This UnitOfWork has been great is that I can do a bunch of stuff to all my repositories and save it in one shot without having a bunch of contexts floating around to synchronize. It may or may not be relevant to this question, but this is how my UnitOfWork uses the repository. There is only 1 repository class, but it can be fed with any entity type needed:
public interface IRepository<T> where T : class
{
IQueryable<T> GetAll();
IQueryable<T> Find(Expression<Func<T, bool>> predicate);
T GetById(int id);
void Remove(T entity);
void Add(T newEntity);
}
public class Repository<T> : IRepository<T> where T : class
{
protected DbContext DbContext { get; set; }
protected DbSet<T> DbSet { get; set; }
public Repository(DbContext dbContext)
{
if (dbContext == null)
{
throw new ArgumentNullException("dbContext");
}
DbContext = dbContext;
DbSet = DbContext.Set<T>();
}
public IQueryable<T> GetAll()
{
return DbSet;
}
// ... more implementation of the interface, nothing fancy
}
The endpoint of where this magic is used is inside my WCF service. This is where I want to actually run through an integration test. A particular method in my service initializes a unit of work and uses that do stuff. The UnitOfWork creates a ReportingDbContext when it is new'd up, and this ReportingDbContext in turn refers to the connection string of "name=ReportingDbContext". After much reading, I think the answer is to use an IoC container like Unity or Ninject (haven't used one before, but I'd like to), and I'm stuck on how to implement IoC in this situation. Here is an example method that I'm using in my WCF service that seems rather hardcoded to the live database connection string:
public ComputerDTO GetComputerDetails(string hostname, string client)
{
// don't worry about the return type, it's defined elsewhere
using (var uoW = new UnitOfWork())
{
var repo = uoW.Computers;
var computer = repo.Find(x => x.Hostname == hostname && x.CompanyEntity.Name == client).FirstOrDefault();
// do stuff
}
}
I'd like to keep my connection strings inside my app.config if at all possible and be able to somehow switch to the testing connection string during the [SetUp] part of my NUnit testing of the methods in my WCF service.
I alway s use a separate unit test project with an App.config of its own. The connection string has the same name as in the main app but the database connection is different.
When you run unit test, e.g. from within Visual Studio, in the background a unit test runner is executed that is nothing but a regular application with its own configuration, the app.config.
You can start and dispose contexts for each test. Most unit test frameworks have attributes to mark methods as setup/teardown fixtures that can either run per test fixture or per test. You could initialize an IoC container in a test fixture setup ([TestFixtureSetUp] in NUnit) and a context in a test setup ([SetUp] in NUnit).
For some scenarios we use scripts to ensure and restore database state, but for most test we start a TransactionScope in the test setup and dispose it (without committing) in the test teardown. This conveniently rolls back any changes made in the test, but the database changes made in the tests are for real.