I am writing unit tests for my service layer, and i completely see the point of creating unit tests to validate logic. For example, if i create a function that adds two numbers, sure write a unit test for this.
But if in my service layer method i have something like this
public ICollection<MyEntity> GetAll()
{
return _context.MyEntities
.Where(e => !e.IsDeleted)
.ToList();
}
What is the point in unit testing this? Since i am getting this from a database, it seems stupid to mock the database, because i am then just assuming that Linq is working as it should be?
Would it not be better to test this against an actual "test" database with sameple data in it. This way i can see if the number of record that are retrieved from the database match what i would expect?
I know that testing against a database, makes this more of a integration test, but is it really valid for unit testing?
What if i take another example, say this
public int Delete(long id)
{
_context.Database.ExecuteCommand("DELETE FROM myTable WHERE Id = ?", id);
return _context.SaveChanges();
}
How can this function be unit tested? If i mock _context.Database and create a unit test that checks if _context.SaveChanges is being called (which i see no point in what so ever), there is no guarntee that it will actually delete my data. WHat if i have a foreign key constraint? The mock would pass, but the actual method would fail really?
I am just starting to think, that unless a method actually calculates some sort of logic, i dont see the point/reason for creating a unit test, especially when using Entity framework?
I think it makes sense to unit test nearly all types of functions:
"What is the point in unit testing this? Since i am getting this from a database, it seems stupid to mock the database, because i am then just assuming that Linq is working as it should be?"
You are not testing Linq, but you are testing the function; the function has the name GetAllAsync; and simply I can assume that this will return all of MyEntity instances stored in database. But it simply returns only deleted items; unit testing is not just verifying if the function works properly; it is also a way to check whether this function is named properly.
Also this function has a problem; what if
_context.MyEntities(e => !e.IsDeleted) returns null? ToList will throw an exception. Then unit testing will help to identify potential problems if you test for extreme values.
Also, unit testing forces you to employ abstraction. If you can not unit test a method, the method may have problems, you need to investigate that method and re-factor.
_context.Database.ExecuteCommand("DELETE FROM myTable WHERE Id = ?", id); In my opinion this line of code needs to stay somewhere else, not in the service layer (in repository maybe?). What if id is "-1"? how will you handle the exception?
I think it is really hard to state a generic rule about not unit testing methods that include Linq.
Why would you unit test a function that adds two numbers? You're not testing the + operator any more than you're trying to test LINQ or EF. You are testing behaviour so it's perfectly valid to test things that you might assume "just work". If, for example, I banned the use of EF in your application, you'd still need a test to ensure correctness in whatever you replaced the function with.
Where do you want to draw the line?
For database related code, I would actually test against a real database, not a mock. It's the only way you can be sure that the SQL is valid (whether you write it by hand or let an ORM generate it for you). There are tools to make that easier, like Respawn.
Related
Just started learning and writing unit testing a day ago so this is probably too simple question:
I have this method in my DBTaskHanlder class that I want to do some unit for, I was able to write one for when ModelState is not valid but now for next one:
public bool CreateTask(ForgotPasswordViewModel fpModel)
{
if (!ModelState.IsValid)
{
return false;
}
try
{
CreateTaskFromModel(fpModel);
_dbContext.SaveChanges();
return true;
}
catch (Exception e)
{
var issue = e.ToString();
throw;
}
}
That CreateTaskFromModel is a private method and well called its job is to create a new row in database on a table.
So I wanted to test when this method is called is one new row getting created in DB?
Is it actually the correct thing to test? How to test ? I don't think we should hit and insert into the real database right?
private void CreateTaskFromModel(ForgotPasswordViewModel fpModel)
{
var message = _dbContext.Create<Message>();
message.MessageType = "TASK".PadLeft(10);
message.Assigned_User_K = fpModel.SendPasswordRequestTo.Trim();
message.Assigned_Date = DateTime.Today;
message.Source_User_K = string.Empty;
message.Target_File_K = "WEBCFGPHRM";
message.Owner_User_K = string.Empty;
message.Message_K = _keyGenerator.Get10ByteBase36Key();
_dbContext.Messages.Add(message);
}
I don't think we should hit and insert into the real database right?
Yes you should. It isn't a "unit test", but it is a valuable test. As you get better at programming, you'll find that most of your bugs are at the edges of your program where it touches other things like databases.
I like writing CRUD tests. One "test method" that actually performs a series of tests. Usually in this pattern:
Create
Read by primary key. Were all the fields properly set?
Read by a collection. You'll get lots of records, is the newly created record in the collection?
Update
Read by primary key. Did the fields change correctly?
Delete
Read by primary key. Nothing was returned, right?
Read by a collection. You'll get lots of records, is the newly created record no longer in the collection? Are the rest of the records still there?
Even though everything is in one big method, treat each step as its own test that happens to use the previous test as a setup.
As Jonathan explained, you do want to test insert, among other operations.
CRUD testing, in my opinion is a very healthy check for your Model that is dealing with database records.
But this is more like integration testing, rather than unit testing.
In order for it to be "pure" unit test, you need to only test that particular functionality. So how do you test method that does db insert without actually inserting anything into database (or having a database, for that matter) ? Mock objects! :)
Here is a similar question to yours that talk about it:
How to unit test an object with database queries
Also a simple google search will help you better understand it.
But bacially, you are mocking a database, or any other object that you need.
For that you probably will need some external library, but that shouldn't be a problem, because mocking is a pretty common thing nowadays.
Some helpful links:
https://msdn.microsoft.com/en-ca/library/ff650441.aspx
https://en.wikipedia.org/wiki/Mock_object
Good Luck!
Lets say I have a class like below.
I'm not sure how I would write a unit/integration test against it. Does it need refactoring?
Would it simply be to add an Add/Find method (which it would have in reality), call the Add in the test then call the Delete and then the Find?
public class Repository
{
public void DeleteProduct(int id)
{
var connstring = ""; //Get from web.config
using(SqlConnection conn = new SqlConnection(connstring))
{
conn.Open();
SqlCommand command = new SqlCommand("DELETE FROM PRODUCTS WHERE ID = #ID")
command.Paramaters.Add("#ID", id)
command.ExecuteNonQuery();
}
}
}
The golden rule is not to test framewkrk's code. Unless this method would have no custom logic there is nothing to test.
I think what you trying to achieve is to separate Repository to make unit-testing easy. The best way of doing this would be to create interface for your repository and mock it.
If you really want to create some integration tests then you have to create some test database where you could make your nuclear bombs experiments.
My suggestion - write an Integration test for repositories (since you are using a framework for data access), unless there is more than CRUD that you are doing in the repository.
Add/Find are all individual Repository methods, and they need to be tested themselves.
I would recommend, use Setup to setup seed data, that you know you can act on. In this case, insert records into Products table.
Then Act: Call Repository.Deleteproduct(<product id created in setup>)
Assert that: Product created in setup is deleted (Query the database again to check).
If you are using an ORM, this test would also test your mappings for Product.
I have never added unit test for database calls. This is definitely more of an integration test. There is nothing observable for you to check.
I know that Java had some tools for this that fitted into JUnit. IT requires that you write XML files that mimic before and after and then it compares the contents of the table to the XML file. I am sure that .Net will have something similar. However I am not sure that it is worth it. I found those tests to be incredibly brittle and provide very little value.
I would suggest take the pragmatic approach and don't write test for database objects. Rather test those object that interact with your database objects.
Currently, I am working on system that does quite a bit of reporting-style functions that consumes many different data points and transforms them into larger, sometimes flattened outputs. Most of my app is built upon a variation of the repository pattern. Due to this, I have a suite of mock-repositories that I use for testing scenarios. The problem that I am running into is that the interaction between these data points is so complex that it is quickly become a maintenance nightmare to maintain the "mock data". Here is a mock example:
public class SomeReportingEntity
{
private IProductRepo ProductRepo;
private IManagerRepo ManagerRepo;
private ILocationRepo LocationRepo;
private IOrdersService OrdersService;
private IEmployeeRepo EmployeeRepo;
public ReportingEntity(IProductRepo ipr, IManagerRepo imr, ILocationRepo ilr, IOrdersService ios,
IEmployeeRepo ier){
//Load these to private vars...
}
//This is the function that I want to test...
public SomeReportingEntity GetManagerSalesByRegionReport()
{
//Make a complex join on all sub collections. These
//sub collections are all under test individually.
var MangerSalesByRegionItems = From x in ProductRepo.CurrentProducts()
Join y in OrdersService.FutureOrders() On ...
Join z in EmployeeRepo.ActiveEmployees() On ...
Join a in LocationRepo.GetAllRegions() On ...
Join b In ManagerRepo.GetActiveManagers On ...
Select new SomeReportingEntity() With { ... }
return MangerSalesByRegionItems.ToList();
}
}
Admittedly, this is a very contrived example but the basic idea that I want to emphasize is that I have several repositories that I am joining and I need to create many tests to ensure that this complex query does as expected. Due to the fact that the joining operations are so complex, it makes the mock data VERY difficult to keep in line - especially as I have to add more associations and test additional points. In addition, I need to be able to enter specific record states into the mocks (such as an employee lacking an assigned manager) to verify that query handles those situations appropriately.
So here are my questions:
What is the best way to "mock" this data so that it is not such a matinenance nightmare? I have had many people suggest building an in-memory database to support this.
Am I really suffering from an architecture issue here? In reporting scenarios, I find myself in this pattern quite a bit where I take many disassociated data points and merge them into a new, hybrid entity. With the onset of Linq, it is very easy to do and has high clarity of intent, but sometimes it feels like I am cheating a little.
The first thing you want to do is make centralized object that knows how to retrieve the data for different repositories. Since this is reporting only, it's easier because you don't have to worry about change tracking.
From a logistical standpoint, one thing I would consider is making a local database to hold the remote data (update periodically using agents). This would remove some of the issues of calling remote services and aggregating their data on the fly. You would also be able to pre-process some of the data at the start.
When I use the repository pattern, I couple it with the Unit Of Work pattern. The Unit of Work is the guy that does all the legwork for you. Theoretically, your UoW could bring in the data from the multiple services and present it to the repositories based on configuration.
For testing, you can use the InMemoryUnitOfWork to provide all the data in one single place.
I've been working on data-heavy project myself. What has worked for us is to use the Repository itself to hydrate objects and then serialize them to XML. We pull the XML file into our test project and use that as the starting point for our automated tests. It's nice because it ensures that your mock data looks like real data.
Our tests tend to look like this...
var object1 = XmlUtil.LoadObject1("filename1");
var object2 = XmlUtil.LoadObject2("filename2");
var result = SomeConverter.Convert(object1, object2);
Assert("somevalue", result.Property1);
If you need to do inline lookups, you can add a mock repository that would provide the same level of dependency injection.
The downside of this approach is if the data schema changes. Sometimes, a test can become obsolete if the data schema has changed. If your schema is still under a lot of flux, I would keep your automated test small until the schema settles down. Focus on unit tests until you know that the schema is relaitively stable.
You have to decide exactly what you want to test.
One way to do this might be to pretend you're using TDD. Pretend that your GetManagerSalesByRegionReport method does not exist (or actually delete it). You'll have to:
Write a failing unit test. What's the simplest thing for it to test: that you can call the method and that it doesn't throw an exception when there's nothing wrong with the data.
You'll need to create the method, empty. It should return void since your test doesn't need it to return anything.
Your test should now pass.
Add a test to ensure that a List of the appropriate type is returned, even if none of the sub-repositories have data.
You'll have to change the method to return your list type, and you'll have to change it to return null. Your test will still fail, so change it to return an empty List and it will pass.
What's left? Those are INNER joins, so you won't get any data back unless all the repositories contain at least one row. So, test for that: create a test where each repo contains one row and ensure the returned list contains the appropriate number of rows. Then, test for the appropriate properties per returned row. Then test that no data is returned if any of the repos contain no rows.
Then, maybe test what happens if some of the repos contain more than one row.
Then, I don't know what would be left to test.
I have a method that takes 5 parameters. This method is used to take a bunch of gathered information and send it to my server.
I am writing a unit test for this method, but I am hitting a bit of a snag. Several of the parameters are Lists<> of classes that take some doing to setup correctly. I have methods that set them up correctly in other units (production code units). But if I call those then I am kind of breaking the whole idea of a unit test (to only hit one "unit").
So.... what do I do? Do I duplicate the code that sets up these objects in my Test Project (in a helper method) or do I start calling production code to setup these objects?
Here is hypothetical example to try and make this clearer:
File: UserDemographics.cs
class UserDemographics
{
// A bunch of user demographic here
// and values that get set as a user gets added to a group.
}
File: UserGroups.cs
class UserGroups
{
// A bunch of variables that change based on
// the demographics of the users put into them.
public AddUserDemographicsToGroup(UserDemographcis userDemographics)
{}
}
File: UserSetupEvent.cs
class UserSetupEvent
{
// An event to record the registering of a user
// Is highly dependant on UserDemographics and semi dependant on UserGroups
public SetupUserEvent(List<UserDemographics> userDemographics,
List<UserGroup> userGroups)
{}
}
file: Communications.cs
class Communications
{
public SendUserInfoToServer(SendingEvent sendingEvent,
List<UserDemographics> userDemographics,
List<UserGroup> userGroups,
List<UserSetupEvent> userSetupEvents)
{}
}
So the question is: To unit test SendUserInfoToServer should I duplicate SetupUserEvent and AddUserDemographicsToGroup in my test project, or should I just call them to help me setup some "real" parameters?
You need test duplicates.
You're correct that unit tests should not call out to other methods, so you need to "fake" the dependencies. This can be done one of two ways:
Manually written test duplicates
Mocking
Test duplicates allow you to isolate your method under test from its dependencies.
I use Moq for mocking. Your unit test should send in "dummy" parameter values, or statically defined values you can use to test control flow:
public class MyTestObject
{
public List<Thingie> GetTestThingies()
{
yield return new Thingie() {id = 1};
yield return new Thingie() {id = 2};
yield return new Thingie() {id = 3};
}
}
If the method calls out to any other classes/methods, use mocks (aka "fakes"). Mocks are dynamically-generated objects based on virtual methods or interfaces:
Mock<IRepository> repMock = new Mock<IRepository>();
MyPage obj = new MyPage() //let's pretend this is ASP.NET
obj.IRepository = repMock.Object;
repMock.Setup(r => r.FindById(1)).Returns(MyTestObject.GetThingies().First());
var thingie = MyPage.GetThingie(1);
The Mock object above uses the Setup method to return the same result for the call defined in the r => r.FindById(1) lambda. This is called an expecation. This allows you to test only the code in your method, without actually calling out to any dependent classes.
Once you've set up your test this way, you can use Moq's features to confirm that everything happened the way it was supposed to:
//did we get the instance we expected?
Assert.AreEqual(thingie.Id, MyTestObject.GetThingies().First().Id);
//was a method called?
repMock.Verify(r => r.FindById(1));
The Verify method allows you to test whether a method was called. Together, these facilities allow you focus your unit tests on a single method at a time.
Sounds like your units are too tightly coupled (at least from a quick view at your problem). What makes me curious is for instance the fact that your UserGroups takes a UserDemographics and your UserSetupEvent takes a list of UserGroup including a list of UserDemographics (again). Shouldn't the List<UserGroup> already include the ÙserDemographics passed in it's constructor or am I misunderstanding it?
Somehow it seems like a design problem of your class model which in turn makes it difficult to unit test. Difficult setup procedures are a code smell indicating high coupling :)
Bringing in interfaces is what I would prefer. Then you can mock the used classes and you don't have to duplicate code (which violates the Don't Repeat Yourself principle) and you don't have to use the original implementations in the unit tests for the Communications class.
You should use mock objects, basically your unit test should probably just generate some fake data that looks like real data instead of calling into the real code, this way you can isolate the test and have predictable test results.
You can make use of a tool called NBuilder to generate test data. It has a very good fluent interface and is very easy to use. If your tests need to build lists this works even better. You can read more about it here.
This is a sample function that works with an entity, saves it to a db and then causes problems because we can't write a Unit Test for it. Check it out:
// this class exists in a Silverlight Class Library
public class EmployeeSaver
{
....
public void Go()
{
Employee e = new Employee();
e.Name="Jeremiah";
... // Other stuff that really needs to be tested
_DataContext.Employees.Add(e);
_DataContext.SubmitChanges();
}
}
Because the nature of RIA Services, a DomainService doesn't run inside of the Silverlight Unit Testing framework. This means I don't have access to RIA when I do my unit tests.
We've thought about mock databases, but this class actually creates an Entity (Employee) to be added to the DB. This is problematic because Mock Databases don't use this entity but a MockEntity class that looks similar to the original entity.
We're not trying to test RIA itself, but how we use the entities generated by RIA.
My end goal would be to write a function similar to this:
[TestMethod]
public void Test()
{
EmployeeSaver s = new EmployeeSaver();
s.Go();
Assert.IsEqual( DataContext.Employees.Last().Name, "Jeremiah" );
}
How can I test this function? What testing framework should I use? Am I way off for using the Silverlight Testing Framework?
In your unit test, instance s needs to have a stubbed out implementation of _DataContext. When the Go method is called, and it calls:
_DataContext.Employees.Add(e);
_DataContext.SubmitChanges();
it will call into your stub. The stub should then record the fact that an employee got added and changes were submitted.
After the call to Go, you should query the stub to ensure that the new employee got added, and call to SubmitChanges occurred.
As a secondary note:
I don't really agree with the last part of the other answer in that you should not care whether Go calls various methods of _DataContext. It is true that you're not concerned about testing _DataContext methods here, but the unit test for Go needs to ensure that the Go method is calling the _DataContext methods properly. The rationale is that every line of the Go method should be testable. If you didn't do this verification, then you could remove the calls to _DataContext method, breaking the code, but the unit test wouldn't catch it. This would break Bob Martin's the "three rules of TDD" principle.
A hand rolled mock database could store your object as is. We use such a system where the repositories are stored in dictionaries of .
You don't even need to go that far though. You could just use a mock interface for the _DataContext with something like RhinoMocks to make sure that the methods you expect to be called were (its not your concern for this test that _DataContext.SubmitChanges() works (that would be up it it's unit test) you only care that Go set the object and called save.