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.
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!
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.
I have question about mock Database. I saw something using moq to mock database call like ExecuteScalar, ExecuteNonQuery and etc. See the link http://www.codeproject.com/Articles/478504/Moq-Mock-Database.
But I am not able to find any information about mock method DiscoverParameters, and ExecuteDataSet.
And repository interface usually a solution for it.
How can I test the DbCommand execute result code with Moq?
I agree that there could definitely be ways in which the database could be mocked. But the real question is should we? Per my understanding mocking makes sense when you are trying to test behaviors. Aren't or shouldn't database tests be state dependent? If am trying to get number of users from a city, and if I am specifically unit testing my database access layer, I would be much more confident if my C# code actually converts in SQL, fire queries and returns real data. The onus of creating and destroying this data surely lies with the developer. It's a problem to maintain test data, but I think it's a good problem to have and solve.
Mocking the data access layer when you unit test layers that depend on it definitely makes sense. But mocking the database itself while testing the data access layer sounds a) like an over kill b) incomplete.
#user3551790 Hi I have mocked ExecuteDataSet using Moq as below
string connectionString = "server=xx.xx.xx.xx;Trusted_Connection=false;user id=user;password=passowrd;database=DBName;Connect Timeout=360;";
var sqlConnection = new SqlConnection(connectionString);
var command = sqlConnection.CreateCommand();
Castle.DynamicProxy.Generators.AttributesToAvoidReplicating.Add(typeof(System.Data.SqlClient.SqlClientPermissionAttribute));
DataSet dsResult = new DataSet();
dsResult.Tables.Add(new DataTable());
dsResult.Tables[0].Columns.Add("Column1");
DataRow dr = dsResult.Tables[0].NewRow();
dsResult.Tables[0].Rows.Add(dr);
dsResult.Tables[0].Rows[0].ItemArray = new object[] { DBNull.Value};
dsResult.Tables.Add(new DataTable());
var mockDb = new Mock<SqlDatabase>(connectionString);
mockDb.Setup(a => a.GetStoredProcCommand("SP_NAME")).Returns(command);
mockDb.Setup(a => a.ExecuteDataSet(command)).Returns(dsResult);
However since DiscoverParameters is a non virtual method you cannot mock it using Moq. You will have to go for Typemock
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.
In bigger projects my unit tests usually require some "dummy" (sample) data to run with. Some default customers, users, etc. I was wondering how your setup looks like.
How do you organize/maintain this data?
How do you apply it to your unit tests (any automation tool)?
Do you actually require test data or do you think it's useless?
My current solution:
I differentiate between Master data and Sample data where the former will be available when the system goes into production (installed for the first time) and the latter are typical use cases I require for my tests to run (and to play during development).
I store all this in an Excel file (because it's so damn easy to maintain) where each worksheet contains a specific entity (e.g. users, customers, etc.) and is flagged either master or sample.
I have 2 test cases which I (miss)use to import the necessary data:
InitForDevelopment (Create Schema, Import Master data, Import Sample data)
InitForProduction (Create Schema, Import Master data)
I use the repository pattern and have a dummy repository that's instantiated by the unit tests in question, it provides a known set of data that encompasses a examples that are both within and out of range for various fields.
This means that I can test my code unchanged by supplying the instantiated repository from the test unit for testing or the production repository at runtime (via a dependency injection (Castle)).
I don't know of a good web reference for this but I learnt much from Steven Sanderson's Professional ASP.NET MVC 1.0 book published by Apress. The MVC approach naturally provides the separation of concern that's necessary to allow your testing to operate with fewer dependencies.
The basic elements are that you repository implements an interface for data access, that same interface is then implemented by a fake repository that you construct in your test project.
In my current project I have an interface thus:
namespace myProject.Abstract
{
public interface ISeriesRepository
{
IQueryable<Series> Series { get; }
}
}
This is implemented as both my live data repository (using Linq to SQL) and also a fake repository thus:
namespace myProject.Tests.Respository
{
class FakeRepository : ISeriesRepository
{
private static IQueryable<Series> fakeSeries = new List<Series> {
new Series { id = 1, name = "Series1", openingDate = new DateTime(2001,1,1) },
new Series { id = 2, name = "Series2", openingDate = new DateTime(2002,1,30),
...
new Series { id = 10, name = "Series10", openingDate = new DateTime(2001,5,5)
}.AsQueryable();
public IQueryable<Series> Series
{
get { return fakeSeries; }
}
}
}
Then the class that's consuming the data is instantiated passing the repository reference to the constructor:
namespace myProject
{
public class SeriesProcessor
{
private ISeriesRepository seriesRepository;
public void SeriesProcessor(ISeriesRepository seriesRepository)
{
this.seriesRepository = seriesRepository;
}
public IQueryable<Series> GetCurrentSeries()
{
return from s in seriesRepository.Series
where s.openingDate.Date <= DateTime.Now.Date
select s;
}
}
}
Then in my tests I can approach it thus:
namespace myProject.Tests
{
[TestClass]
public class SeriesTests
{
[TestMethod]
public void Meaningful_Test_Name()
{
// Arrange
SeriesProcessor processor = new SeriesProcessor(new FakeRepository());
// Act
IQueryable<Series> currentSeries = processor.GetCurrentSeries();
// Assert
Assert.AreEqual(currentSeries.Count(), 10);
}
}
}
Then look at CastleWindsor for the inversion of control approach for your live project to allow your production code to automatically instantiate your live repository through dependency injection. That should get you closer to where you need to be.
In our company we discuss exact these problem a bunch of time since weeks and month.
To follow the guideline of unit testing:
Each test must be atomar and don't allow relate to each other (No data sharing), that means, each tust must be have there own data at the beginning and clear the data at end.
Out product is so complex (5 years development, over 100 tables in a database), that is nearly impossible to maintain this in a acceptable way.
We tried out database scripts, which creates and deletes the data before / after the test (there are automatic methods which call it).
I would say you are on a good way with excel files.
Ideas from me to make it a little well:
If you have a database behind your software google for "NDBUnit". It's a framework to insert and delete data in databases for unit tests.
If you have no database maybe XML is a little more flexible on systems like excel.
Not directly answering the question but one way to limit the amount of tests that need to use dummy data is to use a mocking framework to create mocked objects that you can use to fake the behavior of any dependencies you have in a class.
I find that using mocked objects rather then a specific concrete implementation you can drastically reduce the amount of real data you need to use as mocks don't process the data you pass into them. They just perform exactly as you want them to.
I'm still sure you probably need dummy data in a lot of instances so apologies if you're already using or are aware of mocking frameworks.
Just to be clear, you need to differenciate between UNIT testing (test a module with no implied dependencies on other modules) and app testing (test parts of application).
For the former, you need a mocking framework (I'm only familiar with Perl ones, but i'm sure they exist in Java/C#). A sign of a good framework would be ability to take a running app, RECORD all the method calls/returns, and then mock the selected methods (e.g. the ones you are not testing in this specific unit test) using recorded data.
For good unit tests you MUST mock every external dependency - e.g., no calls to filesystem, no calls to DB or other data access layers unless that is what you are testing, etc...
For the latter, the same mocking framework is useful, plus ability to create test data sets (that can be reset for each test). The data to be loaded for the tests can reside in any offline storage that you can load from - BCP files for Sybase DB data, XML, whatever tickles your fancy. We use both BCP and XML.
Please note that this sort of "load test data into DB" testing is SIGNIFICANTLY easier if your overall company framework allows - or rather enforces - a "What is the real DB table name for this table alias" API. That way, you can cause your application to look at cloned "test" DB tables instead of real ones during testing - on top of such table aliasing API's main purpose of enabling one to move DB tables from one database to another.