How do I write these unit tests? - c#

I'm trying to write unit tests but I'm having trouble figuring out how to delegate functions.
The application is an MVC application and the unit tests depend on moc data (they do not use the database).
We made a change to one of our services, and now the unit tests that test that service are failing. The adjustment I need to make to the unit tests don't seem to work, and this is what I need help with.
First of all, here's how it worked before the change:
The function in the service to be tested:
public Project GetProject(int projectId)
{
return _context.Projects.Find(projectId);
}
Substituting the delegate function in our unit tests:
protected override void Given()
{
GetMockFor<IRiskAliveContext>()
.Setup(ctx => ctx.Projects.Find(1))
.Returns(GetTestProject(1));
}
So essentially, we are say that whenever the service calls context.Projects.Find(1), return the mock project from GetTestProject(1).
This worked fine until we made our change:
public Project GetProject(int projectId)
{
return _context.Projects.Include("Report").FirstOrDefault(p => p.ProjectId == projectId);
}
It doesn't seem we can substitute a delegate function to calls to context.Projects.Include("report").FirstOrDefault(...), at least not in the same way as context.Project.Find(...). When I try to substitute the function as follows, I get a NotSupportedException
protected override void Given()
{
GetMockFor<IRiskAliveContext>()
.Setup(ctx => ctx.Projects.Include("Report").FirstOrDefault(p => p.ProjectId == 1))
.Returns(GetTestProject(1));
}
Is there a different way to substitute a delegate function when the call is to ...Include(...).FirstOrDefault(...)?

For this sort of method, I like to mock the collection (ctx.Projects in this case) and then add a variety of data to that collection to check that the correct filters are applied. For example, in your case, I would add the other projects that have different ProjectIds and confirm that only the correct project is returned as this sort of test will provide a lot more value and you should be able to mock this more easily.
I won't go into the details of how to mock the DbSet or Include as these have been answered in other questions. These questions should be a good starting point:
How to add an item to a Mock DbSet (using Moq)
Moqing Enity Framework 6 .Include() using DbSet<>

Related

How can I unit test a MongoDB query filter?

I have a scenario similar to the following (simplified for clarity):
public class ExampleRepository
{
private readonly IMongoDatabase _db;
public ExampleRepository(IMongoClient mongoClient)
{
this._db = mongoClient.GetDatabase("database");
}
public async Task<IEnumerable<Item>> GetItemsUsingFilter(Guid ownerId, DateTimeOffset createdSince, IEnumerable<ItemType> typesToIgnore)
{
var cursor = await this._db.GetCollection<Item>("Items")
.FindAsync(item =>
item.OwnerId == ownerId
&&
item.CreatedDate >= createdSince
&&
!typesToIgnore.Contains(item.Type)
.SortByDescending(item => item.UserRating)
.Limit(10);
return await cursor.ToListAsync();
}
}
I want to write unit tests to verify the correctness of my query filter (as well as the sort and limit calls), but I can't figure out how to set up the test data to do so.
I've tried mocking the IMongoDatabase and setting up the GetCollection call to return a mock IMongoCollection, but this isn't the right approach, since I need to invoke the FindAsync call on a real MongoCollection.
I looked into changing the repository by splitting out the GetCollection call then applying the filtering using standard LINQ, but I don't want to have to return my entire collection from the DB and then query it in the repository layer.
I've found several examples of people unit testing MongoDB, but these all involved mocking the FindAsync call, which is not what I need to do.
I also considered declaring my filter as an Expression<Func<Item, Boolean>> in a separate class, so I could test that in isolation, but I'd like to explore other options before going down that route, as it adds complexity to the repository layer.
I have not worked with MongoDB, but here's my approach from the perspective of pure unit testing:
Observe that method under test has four inputs: the IMongoClient dependency (which I consider as an indirect input) and three arguments (direct inputs).
Create an object implementing IMongoDatabase (MD) and mock IMongoClient to return it.
Create an object implementing IMongoCollection (MC) and have it returned by MD's GetCollection method; MC is actually your test data.
Define three arguments to pass to method under test.
Now you can perform the test.
Please notice that the implementation of MC includes methods such FindAsync, but that's ok since your purpose is not to test functioning of MongoDB, but to test flow and behavior of your method.
Take a look at this over-simplified example (based on your code):
public async Task<IEnumerable<string>> GetItemsUsingFilter()
{
var cursor = await this._db.GetCollection<string>("Items")
.SortByDescending()
.Limit(10);
return await cursor.ToListAsync();
}
If GetCollection returns in production environment 12 items, "A".."L", we would want "L".."C" to be returned. Moreover, we want our test to fail if for example some other developer mistakenly moves Limit before SortByDescending (which will cause production code to return "J".."A").

Moq Setup does not work as expected in a separate class

I am using moq version 4.2 to unit test some controllers of web api 2 with EF as the ORM. Since a lot of tests need a mocked IEntityRepository<User> so I use a static method in a separate class called TestHelper to create such a fake repository so that I can just call this method in all the tests where needed. Here is the static method:
internal static IEntityRepository<User> GetSingleUserMockRepository(User user, bool noTracking = true, params Expression<Func<User, object>>[] properties)
{
var userRepository = new Mock<IEntityRepository<User>>();
if (properties.Any())
userRepository.Setup(x => x.GetSingleInclude(user.Key, noTracking, properties)).Returns(Task.FromResult(user));
else
userRepository.Setup(x => x.GetSingle(user.Key, noTracking)).Returns(Task.FromResult(user));
return userRepository.Object;
}
I am not showing other method details here because don't think they're relevant to my problem. The thing is when calling this static method in my tests and pass the returned user repository into controllers the test will fail because it cannot find the user i.e. Setup didn't work!. However, if I repeat the test implementation within my tests to create the mock repository as a local variable; everything works fine.
Namely, this doesn't work (where Devices is a navigation property on the User entity, again don't think the detail matters here) e.g. if I pass the returned userRepository into my controller the test will fail.:
var userRepository = TestHelper.GetSingleUserMockRepository(user, true, x=> x.Devices);
But this works e.g. if I just use a local variable in the test and pass the userRepository.Object into my controller everything works as expected:
var userRepository = new Mock<IEntityRepository<User>>();
userRepository.Setup(x => x.GetSingleInclude(user.Key, true, u => u.Devices)).Returns(Task.FromResult(user));
Can someone please explain why? I thought these two ways are equivalent but clearly not in practice.
This is maybe not a full answer (yet), but still to long to fit into a Stack Overflow comment.
When you do:
userRepository.Setup(x => x.GetSingleInclude(user.Key, noTracking, properties)).Returns(...);
you are saying: When GetSingleInclude is called with that user.Key and that noTracking and in particular that properties which is an array of expression trees, Moq shall return what you specify.
However, if Moq gets a call to GetSingleInclude where one or more of the arguments are not equal to the values you supplied, your setup is not relevant, and Moq returns instead the default value which is null.
(If you had used MockBehavior.Strict instead, it would have thrown an exception instead of silently just returning null, which could be more helpful for understanding the issue.)
So when are two arrays of expression trees equal? If Moq uses the default equality comparer for arrays, they are only "equal" when they are the same array instance. If Moq uses some entry-wise comparison, it will come down to whether each expression tree is equal as reference (i.e. same Expression<> instance). In any case you may have trouble.
The question is why it works in the other case. Does GetSingleInclude have special overloads for when the number of properties (expression trees) is little?
What is the result of running the code from this question?
I am saying that you may be facing the same problem as in the thread
Mocking and verifying call to method containing an Expression<Func<T,bool>> parameter.

Mocking the NHibernate JoinAlias with Moq

I have the following repository code that will return a Company object based on an ID value, searching across the standard Company table and an additional table named ExternalCompany.
public Company FindByIdJoin(long id)
{
ExternalCompany xcomp = null;
return Session.QueryOver<Company>()
.Where(p => p.ObjectId == id)
.JoinAlias(p => p.ExternalCompanies, () => xcomp, JoinType.LeftOuterJoin)
.SingleOrDefault<Company>();
}
The code returns values that I expect. However, the trouble I'm having is in writing a Moq unit test to handle the JoinAlias call.
In a simpler method, called FindById, the code is essentially the same except there is no line for JoinAlias. The unit test for this simpler method is:
[Test]
public void FindById_returns_Company_for_valid_Id()
{
// Arrange
Mock<IQueryOver<Company, Company>> mockQueryOver = new Mock<IQueryOver<Company, Company>>();
mockQueryOver.Setup(x => x.Where(It.IsAny<Expression<Func<Company, bool>>>())).Returns(mockQueryOver.Object);
mockQueryOver.Setup(x => x.SingleOrDefault()).Returns(fake_Company);
// Act
var result = _repository.FindById(fake_Company.ObjectId);
// Assert
Assert.IsNotNull(result);
mockQueryOver.VerifyAll();
}
This test works and passes without a problem (fake_Company and _repository are defined elsewhere).
The problem is trying to put a test together for the FindByIdJoin call. I have tried using an additional Setup line like this (which goes between the Where and SingleOrDefault Setup lines):
mockQueryOver.Setup(x => x.JoinAlias(It.IsAny<Expression<Func<Company>>>(), It.IsAny<Expression<Func<ExternalCompany>>>(), JoinType.LeftOuterJoin)).Returns(mockQueryOver.Object);
The system tells me that "the best overloaded method match for IQueryOver ... has some invalid arguments."
So, I tried a few other variations on the Setup, but could not find a workable pattern.
My question is: what Setup arguments will work for JoinAlias so that I can properly test the FindByIdJoin method? Thanks!
The particular overload of JoinAlias you are using is
IQueryOver<TRoot, TSubType> JoinAlias(
Expression<Func<TSubType, object>> path,
Expression<Func<object>> alias,
JoinType joinType);
So, your setup needs to match this. Based on how you setup your IQueryOver mock, the correct setup would then be
mockQueryOver.Setup(x => x.JoinAlias(
It.IsAny<Expression<Func<Company, object>>>(),
It.IsAny<Expression<Func<object>>>(),
JoinType.LeftOuterJoin))
.Returns(mockQueryOver.Object);
Shouldn't MOQ be used for behaviour tests? Such Data access tests seem to be state dependent and I think using mock objects for such a system under test is an overkill.

basic assertions about unit testing

Given the function below - would I be able to assert if the Value "value" was deleted from the user? Or is that assertion part of the tests on the UserService?
Also, what assertions could I test from the function?
public IHttpActionResult Post(string value)
{
var user = authorizationService.GetCurrentUser();
var isDeleted = userService.DeleteValue(value, user);
if (!isDeleted)
{
return NotFound();
}
userService.DeleteProperty(value, user);
var identityResult = userService.Update(user);
if (identityResult.Succeeded)
{
return Ok();
}
return InternalServerError();
}
Yes, you can test that: a unit test doesn't have to be the smallest possible unit per sé but that it may also contain another unit inside of it. By writing tests for both these scenarios you're essentially making a layered project where you have separate tests for the different layers and the value they add to your chain.
You could make the analogy with VAT in a production chain where each test will test the value added in each segment. More information on that here.
This translates to your question as: yes, you can (and should) test whether this action method does what it is supposed to do.
A few examples of tests you could do:
value is null
value is not in the expect format (numeric, negative value, special characters)
The user is not found
a valid value will display Ok()
What you will have to do is make sure that you are not testing against a production database but instead use in-memory repositories (mocking, faking, stubbing, seaming, you name it).
By having these tests in your controller and inside your userService you will know the exact location of the problem in case it isn't working as you want it to:
Test for: Controller Service Conclusion
Works Works Works
Works Doesn't work Faulty tests
Doesn't work Works Controller test failed
Doesn't work Doesn't work Service test failed
While not writing a test for the controller but instead relying on the service would not give you the information that your code actually works.
The line between unit-testing and other types (integration and acceptance testing mainly) is thin because you're testing a bigger part of the system but I still consider it unit-testing since it is contained to the logic of your application and does not use any external resources (database calls get mocked/stubbed/...).

Are those unit tests fine?

I'm trying to grasp test driven development, and I'm wondering if those unit tests is fine. I have a interface which looks like this:
public interface IEntryRepository
{
IEnumerable<Entry> FetchAll();
Entry Fetch(int id);
void Add(Entry entry);
void Delete(Entry entry);
}
And then this class which implements that interface:
public class EntryRepository : IEntryRepository
{
public List<Entry> Entries {get; set; }
public EntryRepository()
{
Entries = new List<Entry>();
}
public IEnumerable<Entry> FetchAll()
{
throw new NotImplementedException();
}
public Entry Fetch(int id)
{
return Entries.SingleOrDefault(e => e.ID == id);
}
public void Add(Entry entry)
{
Entries.Add(entry);
}
public void Delete(Entry entry)
{
Entries.Remove(entry);
}
}
Theese are the unit tests I have written so far, are they fine or should I do something different? Should i be mocking the EntryRepository?
[TestClass]
public class EntryRepositoryTests
{
private EntryRepository rep;
public EntryRepositoryTests()
{
rep = new EntryRepository();
}
[TestMethod]
public void TestAddEntry()
{
Entry e = new Entry { ID = 1, Date = DateTime.Now, Task = "Testing" };
rep.Add(e);
Assert.AreEqual(1, rep.Entries.Count, "Add entry failed");
}
[TestMethod]
public void TestRemoveEntry()
{
Entry e = new Entry { ID = 1, Date = DateTime.Now, Task = "Testing" };
rep.Add(e);
rep.Delete(e);
Assert.AreEqual(null, rep.Entries.SingleOrDefault(i => i.ID == 1), "Delete entry failed");
}
[TestMethod]
public void TestFetchEntry()
{
Entry e = new Entry { ID = 2, Date = DateTime.Now, Task = "Testing" };
rep.Add(e);
Assert.AreEqual(2, rep.Fetch(2).ID, "Fetch entry failed");
}
}
Thanks!
Just off the top of my head...
Although your testing of add really only tests the framework:
You've got adding 1 item, that's good
what about adding LOTS of items
(I mean, ridiculous amounts - for what value of n entries does the container add fail?)
what about adding no items? (null entry)
if you add items to the list, are they in a particular order?
should they be?
likewise with your fetch:
what happens in your fetch(x) if x > rep.Count ?
what happens if x < 0?
what happens if the rep is empty?
does x match performance requirements (what's it's algorithmic
complexity? is it within range when there's just one entry and when
there's a ridiculously large amount of entries?
There's a good checklist in the book Pragmatic Unit Testing (good book, highly recommended)
Are the results right?
Are all the boundary conditions CORRECT
Conform to an expected format
Ordered correctly
In a reasonable range
Does it Reference any external dependencies
Is the Cardinality correct? (right number of values)
does it complete in the correct amount of Time (real or relative)
Can you check inverse relationships
Can you cross check the results with another proven method
Can you force error conditions
Are performance characteristics within bounds
Here's some thoughts:
Positive
You're Unit Testing!
You're following the convention Arrange, Act, Assert
Negative
Where's the test to remove an entry when there's no entry?
Where's the test to fetch an entry when there's no entry?
What is supposed to happen when you add two entries and remove one? Which one should be left?
Should Entries be public. The fact that one of your asserts calls rep.Entries.SingleOrDefault suggests to me you're not constructing the class correctly.
Your test naming is a bit vague; typically a good pattern to follow is: {MethodName}_{Context}_{Expected Behavior} that remove the redundancy "test" redundancy.
As a beginner to TDD I found the book Test-Driven Development By Example to be a huge help. Second, Roy Osherove has some good Test Review video tutorials, check those out.
Before I answer, let me state that I am fairly new to unit testing and by no means an expert, so take everything I state with a grain of salt.
But I feel that your unit tests are largely redundant. Many of your methods are simple pass through, like your AddEntry method is simply a call to the underlying List method Add. Your not testing your code, your testing the Java library.
I would recommend only unit testing methods that contain logic that you write. Avoid testing obvious methods like getters and setters, because they operate at the most basic level. That's my philosophy, but I know some people do believe in testing obvious methods, I just happen to think it is pointless.
Seems fine like this. I personally like to give my tests a bit more descriptive names but that's more of a personal preference.
You can use mocking for dependencies of the class you're testing, EntryRepository is the class under test so no need to mock that, else you would end up testing the mock implementation instead of the class.
Just to give a quick example. If your EntryRepository would use a backend database to store the Entries instead of a List you could inject a mock-implementation for the data-access stuff instead of calling a real database.
This looks like a fine start, but you should try to test the 'borderline' cases as much as possible. Think about what might cause your methods to fail - Would passing a null Entry to Add or Delete be valid? Try to write tests that exercise every possible code path. Writing tests in this manner will make your test suite more useful in the future, should you make any changes to the code.
Also, it is useful for each test method to leave the test object in the same state as when it was invoked. I noticed your TestFetchEntry method adds an element to the EntryRepository, but never removes it. Having each method not affect test object state makes it easier to run series of tests.
You should not be mocking the IEntryRepository since the implementing class is the class under test. You might want to mock the List<Entry> and inject it, then just test that the methods that you invoke via your public interface are called appropriately. This would just be an alternative to the way you have it implemented and isn't necessarily better -- unless you want the class to have it's backing class injected in which case writing the tests that way would force that behavior.
You might want some more tests to make sure that when you insert an entry, the right entry is inserted. Likewise with delete -- insert a couple of entries, then delete one and make sure that the proper one has been deleted. Once you come up with tests to get the code to do what you want it to, keep thinking of ways that you could mess up writing the code and write tests to make sure those don't happen. Granted this class is pretty simple and you may be able to convince yourself that the tests you have that drive behavior is sufficient. It doesn't take much complexity, though, to make it worth testing edge cases and unexpected behavior.
For a TDD beginner and for this particular class, your tests are fine. +1 for making the effort.
Post another question once you get to more complex scenarios involving dependency injection and mocking. This is where things get really interesting ;).
Looks good overall. You should use transactions (or create new instance of repository in TestInitialize) to make sure the tests are trully isolated.
Also use more descriptive test methods, like When_a_new_entity_is_added_to_a_EntryRepository_the_total_count_of_objects_should_get_incremented

Categories