Sorry if this comes across as a stupid question im just not sure how to get started writing some unit tests.
I have a solution containing an api and a unit test project. The api has a repository/interface used for data access using ninject.
My question is how is my best way to unit test my api controllers. I have read a little about Moq but not sure if I need to use it as I want to test against my database.
I have read that I need to use a [TestInitialize] attribute
[TestInitialize]
public void MyTestInitialize()
{
var kernel = NinjectWebCommon.CreatePublicKernel();
kernel.Bind<BusinessController>().ToSelf();
}
My problem is my test project cant resolve CreatePublicKernel
Checking the NinjectWebCommon class in the api there is no function called CreatePublicKernel.
What am I missing here?
Ninject (or other DI library) is used only to provide dependencies into your controller's constructor. E.g. if you need BusinessController which requires two repositories, then controller should have constructor which expects these dependencies:
public BusinessController(IUserRepository userRepository,
IOrderRepository orderRepository)
{
_userRepository = userRepository;
_orderRepository = orderRepository;
}
If you want to write unit tests for your controller, you should provide mocked implementations of these repositories. Use Moq or other framework for creating mocks:
var userRepositoryMock = new Mock<IUserRepository>();
var orderRepositoryMock = new Mock<IOrderRepository>();
// setup mocks here
var controller = new BusinessController(userRepositoryMock.Object,
orderRepositoryMock.Object);
If you are writing integration tests for your controller, you should provide real implementations of these repositories, which use some real database.
var userRepository = new NHibernateUserRepository();
var orderRepository = new NHibernateOrderRepository();
// prepare some data in database here
var controller = new BusinessController(userRepository, orderRepository);
You can move controller instantiation into some method which is executed before each test (SetUp or TestInitialize method) in order to remove code duplication from your tests.
UPDATE: You also can use Ninject for integration testing. Just create Ninject module which will be used both by your real application and integration tests:
public class FooModule : NinjectModule
{
public override void Load()
{
Bind<IUserRepository>().To<NHibernateUserRepository>();
Bind<IOrderRepository>().To<NHibernateOrderRepository>();
Bind<BusinessController>().ToSelf();
}
}
Then use this module both to create kernel in NinjectWebCommon.CreateKernel method and kernel in your tests:
var kernel = new StandardKernel(new FooModule());
var controller = kernel.Get<ValuesController>();
Related
I have a controller class:
#Controller("/x")
class Controller {
#Get
fun index(): String {
return "test test"
}
#Post
fun dopost (userid) = executelogin(login.userId)
}
This controller depends on the executelogin method down below:
fun executelogin(userid) =
do things
If I want to write a unit test, how would I go about using a dependancy injection to introduce a version of the executelogin method. Below is what I have so far and I am not sure if I am doing it correctly:
#MicronautTest
class Controllertest(val method: executelogin()) {
#Inject
lateinit var client: RxHttpClient
#Test
fun testController(){
val request: HttpRequest<String> = HttpRequest.POST("/hello","test")
val body: String = client.toBlocking().retrieve(request)
assertNotNull(body)
assertEquals(method,method)
}
}
Above in the unit test, I am making the executelogin method a paramter for the controllertest class, which I believe is called a method injection. I was wondering if this was the correct way to go about this or if adjustments need to be made. I apologise if some of the code does not quite make sense, I am new to micronaut and the concept of dependancy injections.
If I want to write a unit test, how would I go about using a
dependancy injection to introduce a version of the executelogin
method.
You can't go about using dependency injection to introduce a version fo the executelogin method, at least not directly you can't. Micronaut doesn't support method injection.
This isn't what you asked but just as an FYI... A common thing to do would be to inject some object that contains the method that you want to call.
I'm using ASP.NET Core 3.1 and XUnit for my unit tests.
I built a database context factory class that instantiates an in-memory version of my database:
public static class DbContextFactory
{
public static ApplicationDbContext CreateDbContext()
{
var options = new DbContextOptionsBuilder<ApplicationDbContext>()
.UseInMemoryDatabase(Guid.NewGuid().ToString())
.Options;
var modelBuilder = new ModelBuilder(new ConventionSet());
var dbContext = new ApplicationDbContext(options);
var onModelCreatingMethod = dbContext.GetType().GetMethod("OnModelCreating",
BindingFlags.Instance | BindingFlags.NonPublic);
onModelCreatingMethod.Invoke(dbContext,
new object[] { modelBuilder });
return dbContext;
}
}
This is the current test class I'm trying to use:
public class AdminServiceTests
{
public ApplicationDbContext context { get; set; }
public IAdminService adminService { get; set; }
public AdminServiceTests()
{
this.context = DbContextFactory.CreateDbContext();
this.adminService = new AdminService(userManager, context);
}
[Fact]
public async Task DeleteUserShouldDeleteUser()
{
// What to do ???
}
}
In order for me to test my admin service, I need to provide a user manager. It should be linked with the database I currently have created.
How can I make that happen?
You're making a common mistake of testing the framework. All your test needs to do is ensure that AdminService.DeleteUser calls UserManager.DeleteAsync. Whether or not that spirals down into actually removing the user from the database is 1) not a concern of the service and 2) an implementation detail of both ASP.NET Core Identity and EF Core, both of which have their own extensive test suites to ensure that happens.
As such, you can just use a library like Moq to create a mock of UserManager<TUser> and then do something like:
userManagerMock.Verify(x => x.DeleteAsync(user), Times.Once());
It's worth mentioning here that this also serves to point out a bit of a flaw in this kind of design. You have a dependency on ASP.NET Core Identity whether or not you put an AdminService wrapper around that. Unless your service is doing something special outside of just proxying to UserManager here (e.g. coordinating multiple actions, like maybe deleting the user triggers a notification or something), then your service is pointless, and you should just use UserManager directly. Developers make this kind of mistake constantly; abstraction for the sake of abstraction only hurts your code. It adds additional maintenance concerns, testing concerns, and obscures what the code is actually doing.
Working on a project in ASP.NET Web API 2 which has Autofac as my IoC container. This project is hosted on IIS and in my Autofac module I use the following method to scan for assemblies:
var asm = BuildManager.GetReferencedAssemblies().Cast<Assembly>().ToArray();
Why?
https://docs.autofac.org/en/latest/register/scanning.html#iis-hosted-web-applications
But now we are making Unit Tests using NUnit, during my setup I register my module which uses this method. Now I receive the following exception when running my tests:
System.InvalidOperationException: 'This method cannot be called during the application's pre-start initialization phase.'
I understand why I have this exception but I don't have a clue how to make my code work in tests and for deployment environments.
Setup method of NUnit:
[TestFixture]
public abstract class ApplicationTestBase
{
[SetUp]
public override void Init()
{
var builder = new ContainerBuilder();
// If the class requires auto mapper mapping, initialize them
// We do this in order not to init them for every test => optimalisation!
if (GetType().GetCustomAttributes<RequiresAutoMapperMappingsAttribute>(false) != null)
{
builder.RegisterModule<AutoMapperModule>();
}
this.Container = builder.Build();
}
}
Do I need to create a new module specific for my Unit tests or is there another way for this?
AutoMapperTest
[RequiresAutoMapperMappings]
[TestFixture]
public class AutoMapperTests : ApplicationTestBase
{
[Test]
public void Assert_Valid_Mappings()
{
Mapper.AssertConfigurationIsValid();
}
}
UPDATE
Like Cyril mentioned: Why do you need Ioc in your unit tests? I went searching and indeed you don't have to use the Ioc in your tests. So I ditched the Ioc and initialized my mapper configuration byy doing:
Mapper.Initialize(configuration =>
{
var asm = AppDomain.CurrentDomain.GetAssemblies()
.Where(a => a.FullName.StartsWith("ProjectWebService."));
configuration.AddProfiles(asm);
});
I would recommend separating the "how to load assemblies" logic from the "do assembly scanning and register modules logic."
Right now I'm guessing you have something like this all in one method.
public IContainer BuildContainer()
{
var asm = BuildManager.GetReferencedAssemblies().Cast<Assembly>().ToArray();
var builder = new ContainerBuilder();
builder.RegisterAssemblyTypes(asm);
var container = builder.Build();
}
Not exactly that, but something similar - the loading of assemblies is inlined and directly used.
Separate that so you can swap that logic in for testing. For example, consider allowing a parameter to be optionally passed so you can override the logic in test.
public IContainer BuildContainer(Func<IEnumerable<Assembly>> assemblyLoader = null)
{
IEnumerable<Assembly> asm = null;
if (assemblyLoader != null)
{
asm = assemblyLoader();
}
else
{
asm = BuildManager.GetReferencedAssemblies().Cast<Assembly>().ToArray();
}
var builder = new ContainerBuilder();
builder.RegisterAssemblyTypes(asm);
var container = builder.Build();
}
Your default logic will work the way you want, but then in testing you can swap in something else.
var container = BuildContainer(() => AppDomain.GetAssemblies());
There are lots of ways you can do that swap-in. It could be anything from a static property you can set somewhere to a virtual method you can override somewhere. The point is, by separating the assembly loading logic you can get the test-time behavior to work but still use the registration behavior you're after.
I start to develop a new web application, I create a Domain Object, Inteface, DAL and BLL...
I would like to test all before use that.
If I use the developed function in web application in .net core 2 I put in Startup.cs some code like this :
public void ConfigureServices(IServiceCollection services)
{
**services.AddTransient<ITableOfTableRepository, DBTableOfTableRepository>();**
services.AddMvc();
services.AddSingleton<IConfiguration>(Configuration);
}
And in my Controller add this code
public class TablesController : Controller
{
private readonly ITableOfTableRepository _repository;
public TablesController(ITableOfTableRepository repository)
{
this._repository = repository;
}
How to do a UnitTest project for testing all before of the use in web application?
How to use dependency Injection in unit test?
BR
If you are trying to develop in a test first approach...
You will pass by several steps:
Your test is not compiling because you need to write a controller action and create an interface
Once you created an interface you could mock/stub it (using framework like NSubstitute or others) and inject when you create the controller
var userService = Substitute.For();
...
var controller = new MyController(userService)
you write the controller code for your test to pass
So I've build a WebAPI from scratch, including some best practices that I've found online such as Dependency Injection and Domain<->DTO mapping using auto mapper etc.
My API Controllers now look similar to this
public MyController(IMapper mapper)
{
}
and AutoMapper Registry:
public AutoMapperRegistry()
{
var profiles = from t in typeof(AutoMapperRegistry).Assembly.GetTypes()
where typeof(Profile).IsAssignableFrom(t)
select (Profile)Activator.CreateInstance(t);
var config = new MapperConfiguration(cfg =>
{
foreach (var profile in profiles)
{
cfg.AddProfile(profile);
}
});
For<MapperConfiguration>().Use(config);
For<IMapper>().Use(ctx => ctx.GetInstance<MapperConfiguration>().CreateMapper(ctx.GetInstance));
}
I'm also building a few test cases, implementing MOQ, and this is where i feel a little unsure. whenever calling my controllers, I need to pass in an IMapper like this:
var mockMapper = new Mock<IMapper>();
var controller = new MyController(mockMapper.Object);
But then, how do i configure the IMapper to have the correct mappings? It feels redundant to recreate the same logic I've already created before to configure the Mapper. so I am wondering what is the recommended approach to do this?
That's pretty simple: if you mock IMapper and imagine it as a fully abstract concept of mapping data from one object to another, then you have to treat is an abstraction and not imply there's a real automapper behind it.
First you should not register any existing profile at all, you should instead setup IMapper.Map method to return specific object when given another object.
So for each profile used for specific method you have to do a setup, looking approximately like this:
var mockMapper = new Mock<IMapper>();
mockMapper.Setup(x => x.Map<DestinationClass>(It.IsAny<SourceClass>()))
.Returns((SourceClass source) =>
{
// abstract mapping function code here, return instance of DestinationClass
});
In this case, your test knows nothing about actual IMapper implementation - it just uses it methods to get the data you expect from actual IMapper implementation to receive.
This might me another solution
//auto mapper configuration
var mockMapper = new MapperConfiguration(cfg =>
{
cfg.AddProfile(new AutoMapperProfile()); //your automapperprofile
});
var mapper = mockMapper.CreateMapper();
And then call then controller like so
var controller = new YourController(imapper:mapper,..otherobjects..);
This way it will serve the purpose or else if you create mock object for IMapper then it will return what you ask it to return.