How to UNit test the API controller methods - asp.net-core-webapi

I am really stuck and need your help.
I have a .NET Core 2.1 API and I want to create a nUnitTest project (NUnit 3.10.1) to test the controller of the API but I don't know how to call the controller's action method from the nUnitTest and really need some help.
Things I have tried:
1) Generate parameterless constructor in the controller and instantiate controller from the Test method but that doesn't work.
2) Generate a constructor in the Test class to define the db context but that also doesn't work.
Here is my API Controller:
public class PersonController : ControllerBase
{
private readonly NetCoreAPI1Context _context;
public PersonController(NetCoreAPI1Context context)
{
_context = context;
}
// POST: api/Person
[HttpPost]
public async Task<IActionResult> PostPerson([FromBody] Person person)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
_context.Persons.Add(person);
await _context.SaveChangesAsync();
return CreatedAtAction("GetPerson", new { id = person.Id }, person);
}
}
Here is NetCoreAPI1Context class
public class NetCoreAPI1Context : DbContext
{
public NetCoreAPI1Context(DbContextOptions<NetCoreAPI1Context> options)
: base(options)
{
}
public DbSet<Person> Persons { get; set; }
}
Here is Person class
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
}
I've verified that the PostPerson action in the controller worked.
I then add a nUnitTest project to the solution.
Here is my simple test class and method:
class PersonControllerTest
{
Person _person;
//NetCoreAPI1Context _context;
[SetUp]
public void Setup()
{
_person = new Person
{
FirstName = "David",
LastName = "Johnson",
Email = "dj#dj.com"
};
}
//public PersonControllerTest(NetCoreAPI1Context context)
//{
// _context = context;
//}
[Test]
public void PostPersonTest()
{
var person = _person; // confirm that "person" has data and ready to be used
//
// HOW To CALL THE COTROLLER METHOD PostPerson(...) HERE????
//
}
}

Here is the step about how to NUnit test:
1.In your nUnitTest project,you need to right-click Dependences and choose add reference(Web Api project):
2.WebApi Project Controller:
[Route("api/[controller]")]
[ApiController]
public class PeopleController : ControllerBase
{
private readonly WebApi2Context _context;
public PeopleController(WebApi2Context context)
{
_context = context;
}
// GET: api/People
[HttpGet]
public async Task<ActionResult<IEnumerable<Person>>> GetPerson()
{
return await _context.Person.ToListAsync();
}
// POST: api/People
[HttpPost]
public async Task<ActionResult> PostPerson(Person person)
{
_context.Person.Add(person);
await _context.SaveChangesAsync();
return CreatedAtAction("GetPerson", new { id = person.Id }, person);
}
}
3.nUnitTest project(Be sure that you have installed the package Microsoft.EntityFrameworkCore and Microsoft.EntityFrameworkCore.SqlServer):
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using NUnit.Framework;
using WebApi2.Controllers;
using WebApi2.Data;
using WebApi2.Models;
namespace NUnitTestProject1
{
class PersonControllerTest
{
public static DbContextOptions<WebApi2Context> dbContextOptions { get; }
public static string connectionString = "Server=(localdb)\\mssqllocaldb;Database=YourDatabaseName;Trusted_Connection=True;MultipleActiveResultSets=true";
Person _person;
static PersonControllerTest()
{
dbContextOptions = new DbContextOptionsBuilder<WebApi2Context>()
.UseSqlServer(connectionString)
.Options;
}
[SetUp]
public void Setup()
{
_person = new Person
{
//Id=1,If Id is not designed by using IDENTITY (1, 1),you need to add this line
FirstName = "David",
LastName = "Johnson",
Email = "dj#dj.com"
};
}
[Test]
public void Test1()
{
var context = new WebApi2Context(dbContextOptions);
PeopleController person = new PeopleController(context);
var data = person.PostPerson(_person);
var response = data.Result as CreatedAtActionResult;
var item = response.Value as Person;
Assert.AreEqual("David", item.FirstName);
Assert.AreEqual("Johnson", item.LastName);
Assert.AreEqual("dj#dj.com", item.Email);
}
}
}
4.Result:

Related

unit text mock dbContext

I try to do a unitary test on a repository that returns a Ienumerable. But I have the next mistake:
System.AggregateException : One or more errors occurred. (The source IQueryable doesn't implement IAsyncEnumerable<myNamespace.DTO.UserDTO>. Only sources that implement IAsyncEnumerable can be used for Entity Framework asynchronous operations.)
---- System.InvalidOperationException : The source IQueryable doesn't implement IAsyncEnumerable<myNamespace.DTO.UserDTO>. Only sources that implement IAsyncEnumerable can be used for Entity Framework asynchronous operations.
This my unit test :
//Arrange
var mockSet = Substitute.For<DbSet<User>, IQueryable<User>, IDbAsyncEnumerable<User>>();
((IDbAsyncEnumerable<User>)mockSet).GetAsyncEnumerator()
.Returns(new TestDbAsyncEnumerator<User>(GetUserList().AsQueryable().GetEnumerator()));
((IQueryable<User>)mockSet).Provider.Returns(new TestDbAsyncQueryProvider<User>(GetUserList().AsQueryable().Provider));
((IQueryable<User>)mockSet).Expression.Returns(GetUserList().AsQueryable().Expression);
((IQueryable<User>)mockSet).ElementType.Returns(GetUserList().AsQueryable().ElementType);
((IQueryable<User>)mockSet).GetEnumerator().Returns(GetUserList().AsQueryable().GetEnumerator());
var mockContext = Substitute.For<IMyContext>();
mockContext.Users.Returns(mockSet);
//Act
CancellationToken cancellationToken = new CancellationToken();
UserRepository userRepository = new UserRepository(mockContext);
var users = userRepository.GetListAsync(cancellationToken).Result;
//Assert
Assert.NotNull(users);
My repo I want to test :
public async Task<IEnumerable<UserDto>> GetListAsync(CancellationToken cancellationToken)
{
return await _myContext.Users.Select(u => new UserDto
{
Id = u.Id,
FistName = u.FistName ,
LastName = u.LastName
}).ToListAsync(cancellationToken);
}
What is the problem ?
As covered in the OP comments the doco you're referring to is for EF, not EFCore. You need to implement a different set of interfaces.
The usual advice is to avoid mocking the DbContext however in this case you probably need to as the async operations aren't supported by the in-memory provider. I'm not sure if SQLite supports them. EntityFrameworkCore.Testing should handle this case (disclaimer, I am the author), but you'd need to use your context implementation rather than an interface.
The most common way to get this working is to create implementations of the async interfaces, in the same manner as the EF doco but for EFCore. You'll find most EFCore mocking libraries will do it this way:
public class TestAsyncEnumerable<T> : IAsyncEnumerable<T>, IOrderedQueryable<T>
{
private readonly IEnumerable<T> _enumerable;
private readonly IQueryable<T> _queryable;
public TestAsyncEnumerable(IEnumerable<T> enumerable)
{
_enumerable = enumerable;
_queryable = _enumerable.AsQueryable();
ElementType = _queryable.ElementType;
Expression = _queryable.Expression;
Provider = new TestAsyncQueryProvider<T>(_queryable);
}
public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = new CancellationToken())
{
return new TestAsyncEnumerator<T>(_queryable);
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return _enumerable.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return _enumerable.GetEnumerator();
}
public Type ElementType { get; }
public Expression Expression { get; }
public IQueryProvider Provider { get; }
}
public class TestAsyncEnumerator<T> : IAsyncEnumerator<T>
{
private readonly IEnumerator<T> _enumerator;
public TestAsyncEnumerator(IEnumerable<T> enumerable)
{
_enumerator = enumerable.GetEnumerator();
}
public ValueTask DisposeAsync()
{
return new ValueTask();
}
public ValueTask<bool> MoveNextAsync()
{
return new ValueTask<bool>(_enumerator.MoveNext());
}
public T Current => _enumerator.Current;
}
public class TestAsyncQueryProvider<T> : IAsyncQueryProvider
{
public TestAsyncQueryProvider(IQueryable<T> source)
{
Source = source;
}
private IQueryable<T> Source { get; }
public IQueryable CreateQuery(Expression expression)
{
throw new NotImplementedException();
}
public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
{
return new TestAsyncEnumerable<TElement>(Source.Provider.CreateQuery<TElement>(expression));
}
public object Execute(Expression expression)
{
throw new NotImplementedException();
}
public TResult Execute<TResult>(Expression expression)
{
throw new NotImplementedException();
}
public TResult ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken = new CancellationToken())
{
throw new NotImplementedException();
}
}
This isn't a complete implementation, just what's needed to solve the OP case. The important bit is this line:
public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
{
return new TestAsyncEnumerable<TElement>(Source.Provider.CreateQuery<TElement>(expression));
}
This is what is going to allow the projection to work with the async operation.
Working example:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using AutoFixture;
using KellermanSoftware.CompareNetObjects;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Query.Internal;
using NSubstitute;
using NUnit.Framework;
namespace Question62783423
{
public class Tests
{
[Test]
public void Test1()
{
var fixture = new Fixture();
var users = new TestAsyncEnumerable<User>(fixture.CreateMany<User>());
//Arrange
var mockSet = Substitute.For<DbSet<User>, IQueryable<User>, IAsyncEnumerable<User>>();
((IAsyncEnumerable<User>) mockSet).GetAsyncEnumerator().Returns(users.GetAsyncEnumerator());
((IQueryable<User>) mockSet).Provider.Returns(users.Provider);
((IQueryable<User>) mockSet).Expression.Returns(users.Expression);
((IQueryable<User>) mockSet).ElementType.Returns(users.ElementType);
((IQueryable<User>) mockSet).GetEnumerator().Returns(((IQueryable<User>) users).GetEnumerator());
var mockContext = Substitute.For<IMyContext>();
mockContext.Users.Returns(mockSet);
//Act
var cancellationToken = new CancellationToken();
var userRepository = new UserRepository(mockContext);
var result1 = userRepository.GetListAsync(cancellationToken).Result;
var result2 = userRepository.GetListAsync(cancellationToken).Result;
var comparer = new CompareLogic();
comparer.Config.IgnoreCollectionOrder = true;
comparer.Config.IgnoreObjectTypes = true;
var comparisonResult1 = comparer.Compare(users, result1);
var comparisonResult2 = comparer.Compare(users, result2);
Assert.That(comparisonResult1.Differences.Any(), Is.False);
Assert.That(comparisonResult2.Differences.Any(), Is.False);
}
}
}
public class TestAsyncEnumerable<T> : IAsyncEnumerable<T>, IOrderedQueryable<T>
{
private readonly IEnumerable<T> _enumerable;
private readonly IQueryable<T> _queryable;
public TestAsyncEnumerable(IEnumerable<T> enumerable)
{
_enumerable = enumerable;
_queryable = _enumerable.AsQueryable();
ElementType = _queryable.ElementType;
Expression = _queryable.Expression;
Provider = new TestAsyncQueryProvider<T>(_queryable);
}
public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = new CancellationToken())
{
return new TestAsyncEnumerator<T>(_queryable);
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return _enumerable.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return _enumerable.GetEnumerator();
}
public Type ElementType { get; }
public Expression Expression { get; }
public IQueryProvider Provider { get; }
}
public class TestAsyncEnumerator<T> : IAsyncEnumerator<T>
{
private readonly IEnumerator<T> _enumerator;
public TestAsyncEnumerator(IEnumerable<T> enumerable)
{
_enumerator = enumerable.GetEnumerator();
}
public ValueTask DisposeAsync()
{
return new ValueTask();
}
public ValueTask<bool> MoveNextAsync()
{
return new ValueTask<bool>(_enumerator.MoveNext());
}
public T Current => _enumerator.Current;
}
public class TestAsyncQueryProvider<T> : IAsyncQueryProvider
{
public TestAsyncQueryProvider(IQueryable<T> source)
{
Source = source;
}
private IQueryable<T> Source { get; }
public IQueryable CreateQuery(Expression expression)
{
throw new NotImplementedException();
}
public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
{
return new TestAsyncEnumerable<TElement>(Source.Provider.CreateQuery<TElement>(expression));
}
public object Execute(Expression expression)
{
throw new NotImplementedException();
}
public TResult Execute<TResult>(Expression expression)
{
throw new NotImplementedException();
}
public TResult ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken = new CancellationToken())
{
throw new NotImplementedException();
}
}
public class User
{
public Guid Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class UserDto
{
public Guid Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public interface IMyContext
{
DbSet<User> Users { get; set; }
}
public class UserRepository
{
private readonly IMyContext _myContext;
public UserRepository(IMyContext myContext)
{
_myContext = myContext;
}
public async Task<IEnumerable<UserDto>> GetListAsync(CancellationToken cancellationToken)
{
return await _myContext.Users.Select(u => new UserDto { Id = u.Id, FirstName = u.FirstName, LastName = u.LastName }).ToListAsync(cancellationToken);
}
}

.NET Core identity multiple User types

I have multiple classes (A, B and C) each extends IdentityUser<Guid>. I also have a class called UserRole which extends IdentityRole<Guid>.
The following is my DbContext:
public sealed class EntityDbContext: DbContext
{
public DbSet<A> As { get; set; }
public DbSet<B> Bs { get; set; }
public DbSet<C> Cs { get; set; }
}
I added identities to IServiceCollection:
services
.AddIdentityCore<A>()
.AddEntityFrameworkStores<EntityDbContext>()
.AddRoles<UserRole>()
.AddUserStore<AUserStore>()
// .AddRoleStore<TRoleStore>()
.AddDefaultTokenProviders();
// Same for B, C
I also have the following stores:
public class AUserStore : UserStore<A, UserRole, EntityDbContext, Guid> { }
public class BUserStore : UserStore<B, UserRole, EntityDbContext, Guid> { }
public class CUserStore : UserStore<C, UserRole, EntityDbContext, Guid> { }
The following is the error I'm getting:
Specified argument was out of the range of valid values. (Parameter
'instance 'AUserStore' with ReturnType AUserStore cannot be cast to
IUserStore')
I don't know if what I'm doing is possible or not. Thanks for any help or hint.
Update
I think I got it working:
class GenericUserRoleStore : RoleStore<UserRole, EntityDbContext, Guid> { }
services.AddIdentity<A, UserRole>()
.AddDefaultTokenProviders()
.AddUserStore<AUserStore>()
.AddRoleStore<GenericUserRoleStore>();
services.AddIdentityCore<B>()
.AddRoles<UserRole>()
.AddDefaultTokenProviders()
.AddUserStore<BUserStore>()
.AddRoleStore<GenericUserRoleStore>();
services.AddIdentityCore<C>()
.AddRoles<UserRole>()
.AddDefaultTokenProviders()
.AddUserStore<CUserStore>()
.AddRoleStore<GenericUserRoleStore>();
Both comments on AddIdentity and AddIdentityCore have this:
Adds and configures the identity system for the specified User and Role types.
and,
Compare source code for AddIdentity<> and AddIdentityCore<>,
Review the default code from project template:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, ApplicationRole>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
....
}
I would say: IdentityFramework got confused when you register multiple identity types to it, but we do need it.
I believe what you are looking for are these posts:
Inheritance with EF Code First: Part 1 – Table per Hierarchy (TPH)
Inheritance with EF Code First: Part 2 – Table per Type (TPT)
Inheritance with EF Code First: Part 3 – Table per Concrete Type (TPC)
you have 3 above normal options to map your any UserType data to database. and the 1st options give you best performance, but give you very messive datatable when your usertypes are pretty complex. you would choose either of them for your real project as a balance.
Here is sample code with 1st approach:
public class ApplicationUser : IdentityUser<int>
{
public ApplicationUser() : base()
{
UserRoles = new HashSet<ApplicationUserRole>();
}
public int YearsOfExperience { get; set; }
[InverseProperty("User")]
public virtual ICollection<ApplicationUserRole> UserRoles { get; set; }
}
public class ProjectManager : ApplicationUser
{
public bool Talktive { get; set; }
}
public class Developer : ApplicationUser
{
public bool IsCSharper { get; set; }
}
public class Tester : Developer
{
public bool WhiteBox { get; set; }
}
public class Documenter : Tester
{
public List<string> Languages { get; set; } = new List<string>();
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, int>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
//get following users directly by following properties
public DbSet<ProjectManager> ProjectManagers { get; set; }
public DbSet<Developer> Developers { get; set; }
public DbSet<Tester> Testers { get; set; }
public DbSet<Documenter> Documenters { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
//prevent creating tables for following usertypes
builder.Ignore<ProjectManager>();
builder.Ignore<Developer>();
builder.Ignore<Tester>();
builder.Ignore<Documenter>();
base.OnModelCreating(builder);
builder.Entity<ApplicationUser>(entity =>
{
entity.HasMany(u => u.UserRoles).WithOne(x => x.User).HasForeignKey(c => c.UserId).IsRequired().OnDelete(DeleteBehavior.Cascade);
//tell database to use this column as Discriminator
entity.HasDiscriminator<string>("UserType");
});
builder.Entity<ApplicationRole>(entity =>
{
entity.HasKey(x => x.Id);
});
builder.Entity<ApplicationUserRole>(entity =>
{
entity.HasKey(c => new { c.UserId, c.RoleId });
entity.HasOne(x => x.Role).WithMany(x => x.UserRoles).HasForeignKey(x => x.RoleId).IsRequired().OnDelete(DeleteBehavior.Cascade);
entity.HasOne(x => x.User).WithMany(x => x.UserRoles).HasForeignKey(x => x.UserId).IsRequired().OnDelete(DeleteBehavior.Cascade);
});
}
}
when you need your users:
var allUsers = await _dbContext.Users.ToListAsync();
var allProjectManagers = await _dbContext.ProjectManagers.ToListAsync();
var allDevelopers = await _dbContext.Developers.ToListAsync();
var allTesters = await _dbContext.Testers.ToListAsync();
The next thing you want to configure is UserManager, instead of IUserStore.
public class ApplicationUserManager<TUser, TRole>
where TUser : ApplicationUser
where TRole : ApplicationRole
{
private readonly ApplicationDbContext _context;
private readonly UserManager<TUser> _userManager;
private readonly RoleManager<TRole> _roleManager;
public ApplicationUserManager(ApplicationDbContext context,
UserManager<TUser> userManager,
RoleManager<TRole> roleManager)
{
_context = context;
_userManager = userManager;
_roleManager = roleManager;
}
//customize your own base logics here.
}
public class DeveloperUserManager : ApplicationUserManager<Developer, ApplicationRole>
{
}
public class DocumenterUserManager : ApplicationUserManager<Documenter, ApplicationRole>
{
}
Enjoy it.

Accessing appsettings.json (in WepApi-project) in Class library project

I know this issue has been responded to before, but I cannot seem to get it to work in my case. The solution in Visual Studio contains several project, including WepApi-project (asp.net core), and a class library project. In the class library project I need to access some info in the appsettings.json, residing in the WebApi-project. I've tried to followed different tutorials, which has lead to the following so far:
Appsettings.json
{
"LoginSettings": {
"email": "test#test.com",
"password": "12345678"
}
}
Class modeling configuration (resides in class library project):
LoginSettings
public class LoginSettings
{
public string Email { get; set; }
public string Password { get; set; }
}
Startup.cs (WebApi-project):
public void ConfigureServices(IServiceCollection services)
{
var loginSettings = new LoginSettings
{
Email = Configuration["LoginSettings:email"],
Password = Configuration["LoginSettings:password"]
};
services.AddSingleton(loginSettings);
services.AddOptions();
}
Class in which I need the settings
public static class Test
{
private readonly LoginSettings settings;
public static async Task<string> GetTokenAsync()
{
var email = settings.Email;
...
}
}
I cannot get anything from LoginSettings. In addition, I have tried to make Test-class non-static in order to inject LoginSettings into the constructor. But when I then try to instantiate Test-class, it asks for an instance of LoginSettings. I don't really feel for making Test-class non-static, as it's only purpose is to return a string to another class, and it needs the LoginSettings to do so. What do I do wrong?
Regards.
EDIT
I have made the class Test non-static. What do I pass in when instatiating it?
In the Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<LoginSettings>(Configuration.GetSection("LoginSettings"));
}
In the controller:
public class HomeController : Controller
{
private string _email { get; set; }
private string _password { get; set; }
public HomeController(IOptions<LoginSettings> options)
{
var login = options.Value;
_email = login.Email;
_password = login.Password;
}
public IActionResult GetTokenAsync()
{
// _email: "test#test.com"
// _password: "12345678"
}
}
NOTE: I suggest you name the property name in the appsettings.json like this:
{
"LoginSettings": {
"Email": "test#test.com",
"Password": "12345678"
}
}
Use Email and Password instead of email and password.
UPDATE (for I'm not going to use the LoginSettings in a controller. I'm going to use it in a class in the class library project):
public class MyLib
{
private string _email { get; set; }
private string _password { get; set; }
public MyLib(IOptions<LoginSettings> options)
{
var login = options.Value;
_email = login.Email;
_password = login.Password;
}
public async Task<string> GetTokenAsync()
{
// _email: "test#test.com"
// _password: "12345678"
}
}
UPDATE 2
To use this library. You cannot use it like this:
var lib = new MyLib(???)
Since MyLib (or Test in your example) is a service, you pass it in another constructor before using:
public class AnotherClass
{
private MyLib _lib { get; set; }
public AnotherClass(MyLib lib)
{
_lib = lib;
}
public async Task UseIt()
{
var token = await _lib.GetTokenAsync();
}
}
Ok, I'm trying to explain how it works in my case.
In my ClassLibrary I have the following extension method
public static class MyClassLibraryExtensions
{
public static IServiceCollection AddMyClassLibrary(this IServiceCollection services, LoginSettings options)
{
services.AddSingleton<LoginSettings>(options);
return services;
}
}
then in Web.API project
public void ConfigureServices(IServiceCollection services)
{
services.AddOptions();
var loginSettings = new LoginSettings
{
Email = Configuration["LoginSettings:email"],
Password = Configuration["LoginSettings:password"]
};
services.AddMyClassLibrary(loginSettings);
...
}
and use it
public class Test
{
private readonly LoginSettings _settings;
public Test(LoginSettings loginSettings)
{
_settings = loginSettings;
}
public static async Task<string> GetTokenAsync()
{
var email = _settings.Email;
...
}
}

Unit tests fails after upgrading to .net core 2

Can someone maybe explain to me what this means and why am i getting it.
System.InvalidOperationException : When called from 'VisitLambda',
rewriting a node of type 'System.Linq.Expressions.ParameterExpression'
must return a non-null value of the same type. Alternatively, override
'VisitLambda' and change it to not visit children of this type.
I am getting it from my unit tests I am running the latest .net core 2 with EF core. all my tests were fine till i upgraded then i started getting the error.
The funny thing is, is that when i run the project the line were it fails in the the tests is ok.
This is my Test
[Fact]
public async Task GetUserProfileAsync_Where_Employee_Exist_Test()
{
// Given
var user = TestPrincipal.CreatePrincipalForEmployeeUser();
using (var factory = new TestContextFactory())
using (var context = factory.CreateInMemoryDatabase<ApplicationContext>())
{
this.SetDependencies(context);
var data = EmployeeValueHelper.GetEmployeeValues();
context.AddRange(data);
context.SaveChanges();
var sut = new ProfileService(new DbContextRepository<Data.Models.Employees.Employee>(context), this.userService, this.moqEmploymentStatusService.Object);
// When
// -> this method goes to a service and calls the below FindByIdAsync
var actual = await sut.GetProfileForUserAsync(user);
// Then
Assert.Equal(10, actual.EmployeeId);
}
}
public async Task<Employee> FindByIdAsync(long id)
{
var profile = await this.repository.Set
.Include(_ => _.Address) --> IT FAILS ON THIS LINE, IF I REMOVE THE INCLUDE THEN IT WORKS
.Include(_ => _.EmployeeImage)
.SingleOrDefaultAsync(_ => _.EmployeeId == id);
if (profile == null)
{
return null;
}
return profile;
}
UPDATE
Service Layer
public class ProfileService : GenericService<Employee>, IProfileService
{
private readonly DbContextRepository<Employee> repository;
private readonly IUserService userService;
public ProfileService(DbContextRepository<Employee> repository, IUserService userService)
: base(repository)
{
this.repository = repository;
this.userService = userService;
}
public Task<Employee> GetProfileForUserAsync(ClaimsPrincipal user)
{
var id = this.userService.GetEmployeeId(user);
return id.HasValue ? this.FindByIdAsync(id.Value) : null;
}
public async Task<Employee> FindByIdAsync(long id)
{
var profile = await this.repository.Set
.Include(_ => _.Address)
.Include(_ => _.EmployeeImage)
.SingleOrDefaultAsync(_ => _.EmployeeId == id);
if (profile == null)
{
return null;
}
return profile;
}
}
Employee Model
public class Employee : IValidatableObject
{
[Key]
[Column("pkEmpID")]
public long EmployeeId { get; set; }
[Column("fkCompanyID")]
public long CompanyId { get; set; }
public virtual Company Company { get; set; }
[Display(Name = "lblEmpNumber")]
public string EmpNumber { get; set; }
public virtual IList<Address> Address { get; set; } = new List<Address>();
// WITH SOME EXTRA STUFF NOT NEEDED FOR THIS
}
Repository
public class DbContextRepository<TEntity> : IGenericRepository<TEntity>, IDisposable
where TEntity : class
{
public DbContextRepository(ApplicationContext context)
{
this.Context = context;
this.Set = context.Set<TEntity>();
this.SetWithNoTracking = this.Set.AsNoTracking();
}
public ApplicationContext Context { get; }
public DbSet<TEntity> Set { get; }
public IQueryable<TEntity> SetWithNoTracking { get; }
// WITH SOME EXTRA STUFF NOT NEEDED FOR THIS
}
Hope this will shed more light

Unit Test issues with Entity FrameWork (nullable values)

im trying to implement a uniTest for my application so when i tried to get User by ID value in my application it's work fine, but when i tried to do the same scenario from my unit test class i always get nullable result even if the ID value is correct :
Class AccountController : ApiController
{
private UserService _UserService = null;
public AccountController()
{
_UserService = new UserService();
}
[AllowAnonymous]
[Route("test")]
public IHttpActionResult test()
{
var user = _UserService.getUserById(1); //user --> not null;
}
}
but when i tried a UnitTest Script
[TestClass]
public class userServiceTest
{
private UserService _UserService = null;
public userServiceTest()
{
_UserService = new UserService();
}
[TestMethod]
public void checkUserCase1()
{
var user = _UserService.getUserById(1); //user is null value !!!;
}
}
User Service :
public class UserService
{
private GenericRepository<User> _UserRepository = null;
public UserService()
{
_UserRepository = new GenericRepository<User>();
}
public User getUserById(int id)
{
return _UserRepository.Find(x => x.Id == id).FirstOrDefault();
}
}
The Generic Repository
public class GenericRepository<T> : IGenericRepository<T> where T : class
{
private MyDbContext db = null;
private DbSet<T> table = null;
public IEnumerable<T> Find(Expression<Func<T, bool>> predicate)
{
return table.Where(predicate);
}
}
IGeneric :
public interface IGenericRepository<T> where T : class
{
IEnumerable<T> SelectAll();
T SelectByID(object id);
void Insert(T obj);
void Update(T obj);
void Delete(object id);
void Save();
IEnumerable<T> Find(Expression<Func<T, bool>> predicate);
}
My DB Context :
public class MyDbContext : DbContext
{
public MyDbContext()
: base("AuthWebApiDb")
{
Database.SetInitializer<MyDbContext>(new MyDbInitializer());
}
public DbSet<User> Users { get; set; }
}
I have Two Project : One is the simple project, the second is the Unit Test
Check if EF is innstalled in your UnitTest project.
Put the connection string in the app.config file in the unitest project.
Thank's #Stewart_T

Resources