I m testing an app that my teacher made. I added the driver class, so every order has a driver associated with it, and a put the Driver as a foreign key in my Order class (So I have one to one relationship)
public class Order {
[ForeignKey("Driver")]
public int DriverId { get; set; }
public int Id { get; set; }
public List<Item> Items { get; set; }
}
public class Driver {
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
[Range(1, 5)]
public int Rating { get; set; }
}
Then I went ahead and created the add, update and delete driver, and did the migration and update to the database.
Now I am tryin to test all this functionality, so I made some unit-test but the only ones that are passing are Add_customner and Add_drver everything else fails
So I am hoping to see if anyone can share some light
This are my test
[Test]
public void AddCustomer_ValidCustomer_ReturnsTrue() {
// Arrange
Customer customer = new Customer() {
Id = 1,
FirstName = "James",
LastName = "Cameron",
StreetAddress = "123 Sesame Street",
City = "New York City",
ZIP = "11111",
State = "NY",
PhoneNumber = "1111111111",
Email = "jc#terminator.com"
};
// Act
var result = uow.AddCustomer(customer);
// Assert
Assert.IsTrue(result);
var qCust = _context.Customers.Where(q => q.Id == 1).FirstOrDefault();
Assert.AreSame(qCust, customer);
}
[Test]
public void AddDriver_ValidDriver_ReturnsTrue() {
// Arrange
Driver driver = new Driver() {
ID = 1,
FirstName = "James",
LastName = "Cameron",
Rating = 4
};
// Act
var result = uow.AddDriver(driver);
// Assert
Assert.IsTrue(result);
var qDrive = _context.Drivers.Where(q => q.ID == 1).FirstOrDefault();
Assert.AreSame(qDrive, driver);
}
[Test]
public void RemoveDriver_ValidDriver_ReturnsTrue() {
// Arrange
Driver driver = new Driver() {
ID = 1,
FirstName = "James",
LastName = "Cameron",
Rating = 4
};
// Act
var result = uow.RemoveDriver(driver);
// Assert
var Drivera = _context.Drivers;
Assert.IsTrue(result);
var qDrive = _context.Drivers.Remove(driver);
Assert.AreNotEqual(Drivera, qDrive);
}
[Test]
public void UpdateDriver_ValidDriver_ReturnsTrue() {
Driver driver = new Driver() {
ID = 1,
FirstName = "James",
LastName = "Cameron",
Rating = 4
};
var result = uow.UpdateDriver(driver);
var qDrive = _context.Drivers.Where(q => q.ID == 1).FirstOrDefault();
Assert.AreSame(qDrive, driver);
}
}
}
For it to work it must return true
Make sure your UOW using the same object as _context? Make sure when setting up mocks your database context it is injected and assigned same object to UOW and _context. This might be the reason your read-only operations are passing but others are failing.
Since you name it _context, I assume it is an instance variable of your test class. So whenever a test run, a new test object create and thus _context. To test your operations other than add, you should assume the _context is empty. That means you should first add the driver and then test removing it.
Related
New to XUnit and attempting to test the following method but test is failing.
I believe the reason is that a new instance of the data is created when the assert is called.
So even thought the results are the same the object reference is not.
When a new record is added to the collection, it is supposed to returned the same record added.
Employee Data Class:
public class EmployeeData
{
public int Id { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
public string Title { get; set; }
}
Method to test:
public List<EmployeeData> Add(List<EmployeeData> employees)
{
foreach(var employee in employees)
{
data.Add(new EmployeeData() { Id = newId(),
FirstName = employee.FirstName, LastName = employee.LastName,
Title = employee.Title });
}
return data;
}
Test Method:
[Fact]
public void Add()
{
// Arrange
var data = new List<EmployeeData>();
data.Add(new EmployeeData() { Id = 1, FirstName = "Adams", LastName = "John", Title = "Fireman" });
// Mocking the employee class constructor arguments.
var mockLogging = new Mock<ILogger<DataService>>();
var mockConfig = new Mock<IConfiguration>();
var sut = new Employee(mockLogging.Object, mockConfig.Object);
var result = sut.Add(data);
// Assert should return the exact data inputted
Assert.Equal(result, data);
}
Test Result:
Message:
Assert.Equal() Failure
Expected: List<EmployeeData> [EmployeeData { FirstName = "Adams", Id = 1, LastName = "John", Title = "Fireman" }]
Actual: List<EmployeeData> [EmployeeData { FirstName = "Adams", Id = 1, LastName = "John", Title = "Fireman" }]
What does it mean that EmployeeData equals EmployeeData?
You can override Equals methods in the EmployeeData class.
public override bool Equals(object obj)
{
return this.FirstName == ((EmployeeData)obj).FirstName;
}
The second option is to pass IEqualityComparer<T> to the Equal method.
public class GenericCompare<T> : IEqualityComparer<T> where T : class
{
private Func<T, object> _expr { get; set; }
public GenericCompare(Func<T, object> expr)
{
this._expr = expr;
}
public bool Equals(T x, T y)
{
var first = _expr.Invoke(x);
var sec = _expr.Invoke(y);
if (first != null && first.Equals(sec))
return true;
else
return false;
}
public int GetHashCode(T obj)
{
return obj.GetHashCode();
}
}
And use it:
Assert.Equal<EmployeeData>(result, data, new GenericCompare<EmployeeData>(x => x.Id));
Copy pasted GenericCompare from https://stackoverflow.com/a/23623976/6629020
I have a previous question that shows how my models look and it was adding FAKE data. Add to Existing Model based on a POCO with need to add to List<T>
Now I am wanting to add REAL data and i'm wondering how to do this. Should or need I loop over the result ??
public IActionResult FindPerson (FindPersonViewModel findPersonViewModel)
{
var firstName = findPersonViewModel.FirstName;
var middleName = findPersonViewModel.MiddleName;
var lastName = findPersonViewModel.LastName;
var emailAddress = findPersonViewModel.EmailAddress;
var genderTypeId = findPersonViewModel.GenderTypeId;
// GET REAL DATA
using (AzEdsIdentityContext context = new AzEdsIdentityContext(AzEdsIdentityContext.Options))
{
var result = context.FindPerson(firstName, lastName, genderTypeId);
// for loop on the result to hydrate new List<FindPersonResultsViewModel>() ?
}
// Note: here is exactly how I hydrated the model with fake data
findPersonViewModel.findPersonResultsViewModel = new List<FindPersonResultsViewModel>()
{ new FindPersonResultsViewModel { AZEDID = 33423432, PersonID = 3534454, FirstName = "John", LastName = "Williamson", MiddleName = "K", ExistInContactManager = false, ActionType = true, ContactType = "Principal", DOB = "5/1/1985", PhysicalAddress = "123 main st. mesa, az.", PreferredEmail = "john#aol.com", PreferredPhone = "602-393-4443"},
new FindPersonResultsViewModel { AZEDID = 33423432, PersonID = 3534454, FirstName = "Jon", LastName = "Williamson", MiddleName = "K", ExistInContactManager = false, ActionType = true, ContactType = "Principal", DOB = "5/1/1985", PhysicalAddress = "123 main st. mesa, az.", PreferredEmail = "john#aol.com", PreferredPhone = "602-393-4443"},
};
}
Given the Person model
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}
And you obtain the result from your context
List<Person> result = context.getPersons();
You need a collection of a different but similar type, so you use a projection
List<PersonViewModel> result =
context.getPersons()
.Select(p => new FindPersonResultsViewModel
{
Name = p.Name,
Email = p.Email
}).ToList();
Then assign the collection property to another model
var model = new ResultViewModel
{
...
findPersonResultsViewModel = result
};
If you're getting back IEnumerable, do .ToList() to get the List<T>.
I want to test the following method:
public ActionResult Index()
{
var transactions = db.Transactions.Include(t => t.User)
.GroupBy(t => t.UserId)
.Select(group => new TransactionViewModel
{
User = group.FirstOrDefault().User.FullName,
UserId = group.FirstOrDefault().UserId,
Total = (group.Sum(t => t.TransactionAmount))
});
// Show lowest balance first
return View(transactions.ToList());
}
Here the Transaction model has a list of Orders, has a foreign key to User and some more properties, see:
public class Transaction
{
public int TransactionId { get; set; }
public DateTime Date { get; set; }
public int UserId { get; set; }
public List<Order> Orders { get; set; }
public decimal TransactionAmount { get; set; }
public virtual User User { get; set; }
}
The TransactionViewModel looks as follows:
public class TransactionViewModel
{
public string User { get; set; }
public int UserId { get; set; }
public decimal Total { get; set; }
}
and is used to calculate the Total of different transactions belonging to a user.
To test this method I have a FakeDbSet and use a FakeContext (which both work in tests of other controllers) in the following Setup:
[TestClass]
public class TransactionControllerTest
{
TransactionController trController;
[TestInitialize]
public void TransactionControllerTestInitialize()
{
// Arrange
var memoryTransactionItems = new FakeDbSet<Transaction>
{
new Transaction {
Date = DateTime.Today,
TransactionAmount = 5.10M,
UserId = 1,
Orders = new List<Order>{
// Categorie 2 and confirmed
new Order { OrderId = 2,
UnitPrice = 2.00M,
Quantity = 1,
Date = DateTime.Today,
IsConfirmed = true,
User = new User {
Name = "Kees",
FullName="Kees Piet",
Email = "Kees#DeHond.nl",
isAvailable = true,
UserId = 1
},
Product = new Product {
Category = new Category {
CategoryId = 2,
Name = "Categorie2"
},
Name = "Testproduct2",
Price = 2.00M,
Visible = true
}
},
// Categorie 2 and confirmed
new Order { OrderId = 2,
UnitPrice = 1.00M,
Quantity = 1,
Date = DateTime.Today,
IsConfirmed = true,
User = new User {
Name = "Jan",
FullName="Jan Piet",
Email = "Jan#DeBouvrier.de",
isAvailable = true,
UserId = 2
},
Product = new Product {
Category = new Category {
CategoryId = 2,
Name = "Categorie2"
},
Name = "Testproduct2",
Price = 3.10M,
Visible = true
}
}
}
}
};
// Create mock units of work
var mockData = new Mock<FakeContext>();
mockData.Setup(m => m.Transactions).Returns(memoryTransactionItems);
// Setup controller
trController = new TransactionController(mockData.Object);
}
[TestMethod]
public void TestTransactionIndex()
{
// Invoke
var viewResult = trController.Index() as ViewResult;
var transactionsFromView = (IEnumerable<TransactionViewModel>)viewResult.Model;
// Assert
Assert.AreEqual(1, transactionsFromView.Count(),
"The amount of transactions added to the Index View should be 1.");
}
}
When I run the TestTransactionIndex I get the following error:
Test Name: TestTransactionIndex Test Outcome: Failed Test
Duration: 0:00:30.6276475
Result Message: Test method
Tests.Controllers.TransactionControllerTest.TestTransactionIndex threw
exception: System.NullReferenceException: Object reference not set to
an instance of an object. Result StackTrace: at lambda_method(Closure
, IGrouping2 ) at
System.Linq.Enumerable.WhereSelectEnumerableIterator2.MoveNext()
at System.Collections.Generic.List1..ctor(IEnumerable1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source) at
Controllers.TransactionController.Index()
I find this strange since I setup my mock units in the proper way. I hope someone can explain how I can properly send the FakeDbSet<Transaction> to the view and not get a NullReferenceException.
/Edit As requested, here are the contructors for TransactionController:
private IContext _context;
public TransactionController()
{
_context = new Context();
}
public TransactionController(IContext context)
{
_context = context;
}
The query in your index method includes the line:
db.Transactions.Include(t => t.User)
And the Select part of the query is using the User property in the Transaction class to populate the TransactionViewModel as in
User = group.FirstOrDefault().User.FullName,
That line will throw a NullReferenceException if the User property in the Transaction is null. So you need the result of that query to contain a not null User property when executed in your unit test using the fake objects.
I am not sure how your fake context and DbSets work, but the easiest thing to try is to populate the User property of the Transactions in your fake memoryTransactionItems.
You may also try adding a fake users dbset as in the next code snippet (I'm assuming you have a Users DbSet in your EF context):
var memoryUsers = new FakeDbSet<User>
{
new User{ UserId = 1, ... },
...
};
mockData.Setup(m => m.Users).Returns(memoryUsers);
I'm using EF code first and I have two classes that inherited from a base class(TPT):
public class Party
{
public int PartyId {get; set;}
}
public Person:Party
{
string FirstName { get; set; }
string LastName { get; set; }
}
public Organization:Party
{
string Name { get; set; }
}
Now, I want to create a query to fetch all Persons that their LastNames are equal to "SomeName" and all Organizations that their Name begins with "A" in one transaction.
Something like this
IList<Party> GetParties(string name, string organizationName)
{
IList<Party> result = new List<Party>();
using(var context = new MyContext())
{
var persons = context.Parties.OfType<Person>().Where(t=>t.LastName = name) ;
var organizations = context.Parties.OfType<Organization>().Where(t=>t.Name.StartWith(organizationName));
//return merge of persons and organizations
}
}
Is there any way to do this?
You can do
context.Parties.OfType<Person>().Where(t=>t.LastName = name).OfType<Party>()
.Concat(context.Parties.OfType<Organization>()
.Where(t=>t.Name.StartWith(organizationName)))
You don't have to cast the second collection to Party because it is concatenated with an IQueryable<Party> which is covariant with IQueryable<Organization>.
I did some LINQPad fiddling and I believe that this is the result you want.
IList<Party> GetParties(string name, string organizationName)
{
IList<Party> result = new List<Party>();
using(var context = new MyContext())
{
var persons = context.Parties.OfType<Person>().Where(t=>t.LastName = name) ;
var organizations = context.Parties.OfType<Organization>().Where(t=>t.Name.StartWith(organizationName));
//return merge of persons and organizations
result = (IList<Party>)persons.Union((IEnumerable<Party>)organizations);
}
return result;
}
I have an entity called ActionResult that my methods along the application returns. Now i want to map a returned object in the ActionResult to it's right place in an array of that object...
public class Core
{
public Employee[] Employees = new[] {
new Employee {
Name = "Jack",
Age = 21,
Salary = 1000
},
new Employee {
Name = "Carl",
Age = 35,
Salary = 1000
},
new Employee {
Name = "Tom",
Age = 41,
Salary = 1000
},
};
}
public class ActionResult
{
public string ActionID { get; set; }
public Employee Employee { get; set; }
}
public class Employee
{
public String Name { get; set; }
public int? Age { get; set; }
public int? Salary { get; set; }
public int? Level { get; set; }
}
public ActionResult MethodThatReturnsActionResultWithAnEmployee()
{
return new ActionResult {
ActionID = new Guid().ToString(),
Employee = new Employee {
Name = "Carl",
Age = 35,
Salary = 7000,
Level = 1
}
};
}
Now as you can see what i want to do is taking the Employee that is returned from the Method, and search in the array of Employees in the Core and update it using the new given data using AutoMapper.
AutoMapper will not search employee in some array for you. How it would know which employees should be considered as equal? You should search for employee manually, and use appropriate mapping method to update existing instance of employee with data from other employee instance:
Mapper.CreateMap<Employee, Employee>();
var result = MethodThatReturnsActionResultWithAnEmployee();
var employee = result.Employee;
var core = new Core();
var employeeToUpdate =
core.Employees.FirstOrDefault(e => e.Name == employee.Name);
Mapper.Map(employee, employeeToUpdate);
If you really want mapping to look like
Mapper.Map(result, core);
Then you should write your own type mapper for this:
public class ActionResultToCoreConverter : ITypeConverter<ActionResult, Core>
{
public Core Convert(ResolutionContext context)
{
var result = (ActionResult)context.SourceValue;
var employee = result.Employee;
var core = (Core)context.DestinationValue ?? new Core();
var employeeToUpdate =
core.Employees.FirstOrDefault(e => e.Name == employee.Name);
Mapper.Map(employee, employeeToUpdate);
return core;
}
}
And mapping will look like:
Mapper.CreateMap<Employee, Employee>(); // this map also required
Mapper.CreateMap<ActionResult, Core>()
.ConvertUsing<ActionResultToCoreConverter>();
var result = MethodThatReturnsActionResultWithAnEmployee();
var core = new Core();
Mapper.Map(result, core);
// if you want to create new Core instanse:
var core2 = Mapper<Core>(result);