Unit Test for calling stored procedure - c#

I have a method that calls the stored procedure using Entity Framework and returns the query result.
How I can write a unit test for this method? I am not sure how mock the call and return values.
Stored procedure is returning me 3 columns.
public VerifyUser VerifyUser(string accountKey)
{
try
{
LoansContext loansContext = new LoansContext();
VerifyUser queryResult = null;
using (loansContext)
{
using (loansContext.Database.Connection)
{
loansContext.Database.Connection.Open();
string sqlStatment = string.Format("{0} #AccountKey = '{1}'", "execute [Loan].[Proc_VerifyUser]", accountKey);
queryResult = loansContext.Database
.SqlQuery<VerifyUser>(sqlStatment)
.Single();
}
}
}
catch (Exception exception)
{
LoansDomainTrace.Trace.Error(EventId.Retrieve,
() => string.Format("VerifyUser exception: {0}", exception.Message), exception);
throw;
}
}

In such cases I like to unit test my method logic and then isolate the code I want to test (in your case VerifyUser) from external resources (e.g. DBs). I good option is with some sort of in-memory EF provider, however a much more common way is to abstract away your EF implementation e.g. with some sort of repository pattern. Without this isolation any tests you write are integration, not unit tests.

Related

How to create unit test for testing data insertion methods with Entity Framework?

I'm trying to create unit tests for methods that insert data into a SQL Server database in ASP.NET MVC. I've got several ActionResult methods that write data into my SQL Server database. One of these methods is this the following:
[HttpPost]
public ActionResult AddApi(ApiRedirect model)
{
try
{
List<ApiRedirect> list = dbProducts.ApiRedirects.ToList();
int companyID = dbProducts.Companies.Where(x => x.CompanyName == model.Company.CompanyName).FirstOrDefault().CompanyID;
int mappingID = dbProducts.MappingNames.Where(x => x.Name == model.MappingName.Name).FirstOrDefault().MappingID;
ApiRedirect api = new ApiRedirect();
api.ApiName = model.ApiName;
api.CompanyID = companyID;
api.ApiURL2 = model.ApiURL2;
api.MappingID = mappingID;
api.ResponseType = model.ResponseType;
dbProducts.ApiRedirects.Add(api);
dbProducts.SaveChanges();
return View ();
}
catch (Exception ex){
throw ex;
}
}
However when I try to this in my test project like this:
[TestClass]
public class ApiRedirectTests
{
[TestMethod]
public void AddApiRedirect()
{
//Arrange
var controller = new ApiBrokerController();
ApiRedirect model = new ApiRedirect();
model.ApiName = "UnitTest";
model.CompanyID = 1;
model.ApiURL2 = "www.UnitTest.com/API";
model.MappingID = 1;
model.ResponseType = "json";
//Act
controller.AddApi(model);
}
}
I'm getting the following error:
I would like some test that writes code, checks if code is inserted in database and delete afterwards. What is the best way to do that?
UPDATE
I've added MVC reference to my project and now I get the following error:
Thanks in advance!
what you are talking about is an integration test not a unit test.
you will have:
a call which creates some data
another which does the actual test / asserts against your criteria
a final one which deletes the test data created in step one.
You have a number of ways of doing this, one in code, you write code which talks to endpoints only, you don't need to instantiate a controller at all.
What you must ensure you have is a way to create / delete data in an API kind of way, so you need endpoints which do this.
If you don't want to write code, you can also use something like Postman which can quite nicely orchestrate all this. This gives you the certainty that everything works, from the endpoints which clients will use, all the way down to database.
Error number 1
To fix your error, add the System.web.mvc framework to your unit test
PM> Install-Package Microsoft.AspNet.Mvc – gh9 20 mins ago
Error Number 2
You now need to upgrade the System.web version to 5.2 from 4.0
Try adding this Nuget Package

Unit testing a method which Posts and Deletes by selection C#

I have this method which selects one row of a table and copies it to the another table and then it just deletes it from the first one. The problem is that how can I unit test it because it executes two methods (Post and Delete) at the same time.
Here is the method:
public ActionResult Pay(int id, Car car)
{
try
{
using (BookCarDBEntities db = new BookCarDBEntities())
{
var carToDelete = db.Cars.FirstOrDefault(c => c.Id == id);
var book = CreateNewBooking(carToDelete);
db.Bookings.Add(book);
db.Cars.Remove(carToDelete);
db.SaveChanges();
return RedirectToAction("ListBookings", "Home");
}
}
catch (Exception ex)
{
return View(ex + "error");
}
}
private Booking CreateNewBooking(Car car)
{
var bookingCreated = new Booking
{
id = car.Id,
model = car.model,
make = car.make,
price = car.price,
location = car.location
};
return bookingCreated;
}
It does not matter how many external function calls your method to have. To get the values from the method calls in your method (that you wanna unit test), you should mock those methods to return certain responses when called with certain parameters.
You should check Moq to learn how to mock methods. Also, I suggest you wrap your methods with an interface (BookCarDBEntities). It is more important to write code to testable rather than writing tests to unmanageable code. Hope this helps.

How to unit test code that includes a database transaction

How to put unit around the below codes:
public DbContextTransaction QTTransactionBegin()
{
return Database.BeginTransaction();
}
public int CreateCampaign(CreateCampaignModel createCampaignModel)
{
using (var transaction = _qtContext.QTTransactionBegin())
{
try
{
var campaign = new Campaign();
campaign.CampaignCode = createCampaignModel.CampaignCode;
campaign.CampaignDescription = createCampaignModel.CampaignDescription;
campaign.CampaignDate = createCampaignModel.CampaignDate;
campaign.CampaignNotes = createCampaignModel.CampaignNotes;
campaign.OwnerUserID = createCampaignModel.OwnerUserID;
campaign.AddedOn = DateTime.Now;
campaign.AddedBy = createCampaignModel.OwnerUserName;
campaign.UpdatedOn = DateTime.Now;
campaign.UpdatedBy = createCampaignModel.OwnerUserName;
campaign.CampaignSegments = GetCampaignSegmentList(createCampaignModel);
var campaignId = AddOrUpdateCampaign(campaign);
transaction.Commit();
return campaignId;
}
catch (Exception ex)
{
transaction.Rollback();
}
}
return 0;
}
Could anyone advise me how to put unit test around above code ?
I tried the code as below :
Database_database;
[TestInitialize]
public void SetUp()
{
_qtDALMock = _factory.CreateMock<IQTDAL>();
_campaignRepository = new CampaignRepository(_qtDALMock.MockObject);
}
[TestMethod]
public void Check_CreateCampaign_Test()
{
// arrange
const int expectedCampaignId = 1;
var createCampaign = QueryToolDummies.CreateCampaignModel;
_database.BeginTransaction();
_qtDALMock.Expects.One.MethodWith(x => x.QTTransactionBegin())
.WillReturn(_database.BeginTransaction());
_qtDALMock.Expects.One.Method(x => x.AddOrUpdateCampaign(null))
.With(Is.TypeOf<Campaign>())
.WillReturn(expectedCampaignId);
// act
var result = _campaignRepository.CreateCampaign(createCampaign);
// assert
Assert.IsNotNull(result);
}
this _database.BeginTransaction() has a problem. the error says can't use like it.
Please advise.
One question? Why are you trying to start a transaction into a unit test?
Will be easy if you Mock your repository using Moq framework and return what you need to return from the repo.
In fact, I thought that start a BeginTransaction() in a unit test is not a good practice.
I hope this helps
I've experienced the same issue, it's quite tricky to work around.
I tried creating a wrapper class for the context that exposes a BeginTransaction() method, but ultimately you end up needing to mock the DbContextTransaction returned by BeginTransaction() when it comes to testing, but DbContextTransaction has neither an interface or a public constructor.
In the end I wrote a transaction manager class that creates and manages its own transaction and exposes methods for beginning, committing and rolling back the transaction. That manager class, and the service that returns it, can then be faked allowing the code using transactions to be fully tested.
I've written that up fully in this answer.
You are trying to unit test more than one unit.
Assuming that the code above is your 'data layer' / repository then you are performing an integration test because more than a single unit is involved in the test.
You could include setup / teardown for the database within your test class and call the SUT (subject under test) with valid and invalid data to validate expected behaviours.

Cannot return type IQueryable or IEnumerable

Since I cannot return either of these types from a Linq to Entities query, I am sticking with returning a List.
On return from the DB call (which is in a separate WCF service or DLL), the code in the Controller fails because the dbcontext connection is closed.
Note the code in the following. For both IEnumerable and IQueryable, the data does not come back because of the above description.
Method in MVC Controller
// Controller
IEnumerable<ProjectDescription> projectDdl = db.GetProjectDropDownList().AsEnumerable();
// Error coming back because dbcontext connection was closed.
ViewBag.ProjectsCust = new SelectList(projectDdl, "ProjectId", "Name");
Method in WCF service or DLL
// WCF Service or DLL
public IEnumerable<ProjectDescription> GetProjectDropDownList()
{
try
{
//IQueryable<ProjectDescription> project = null;
using (YeagerTechEntities DbContext = new YeagerTechEntities())
{
DbContext.Configuration.ProxyCreationEnabled = false;
DbContext.Database.Connection.Open();
IEnumerable<ProjectDescription> project = DbContext.Projects.Select(s =>
new ProjectDescription()
{
ProjectID = s.ProjectID,
Description = s.Description
}
);
return project;
}
}
catch (Exception ex)
{
throw ex;
}
}
I even tried the following establishing a DbContext instance before the DB call which still didn't work actually trying to pass down the DbContext to the DB method.
Controller:
DbContext = new YeagerTechEntities();
IEnumerable<ProjectDescription> projectDdl = db.GetProjectDropDownList(DbContext).AsEnumerable();
ViewBag.ProjectsCust = new SelectList(projectDdl, "ProjectId", "Name");
DbContext.Dispose();
DB method:
public IEnumerable<ProjectDescription> GetProjectDropDownList(YeagerTechEntities DbContext)
{
try
{
//IQueryable<ProjectDescription> project = null;
DbContext.Configuration.ProxyCreationEnabled = false;
DbContext.Database.Connection.Open();
IEnumerable<ProjectDescription> project = DbContext.Projects.Select(s =>
new ProjectDescription()
{
ProjectID = s.ProjectID,
Description = s.Description
}
);
return project;
}
catch (Exception ex)
{
throw ex;
}
}
The only thing that worked besides using List was to actually place the DB method inside the Controller, which obviously is not good practice whatsoever.
Here is the List convention that works fine:
Controller:
IEnumerable<ProjectDescription> projectDdl = db.GetProjectDropDownList();
ViewBag.ProjectsCust = new SelectList(projectDdl, "ProjectId", "Name");
DB method:
public List<ProjectDescription> GetProjectDropDownList()
{
try
{
using (YeagerTechEntities DbContext = new YeagerTechEntities())
{
DbContext.Configuration.ProxyCreationEnabled = false;
DbContext.Database.Connection.Open();
IEnumerable<ProjectDescription> project = DbContext.Projects.Select(s =>
new ProjectDescription()
{
ProjectID = s.ProjectID,
Description = s.Description
}
);
List<ProjectDescription> myProjects = new List<ProjectDescription>();
myProjects = project.ToList();
return myProjects;
}
}
catch (Exception ex)
{
throw ex;
}
}
If anyone can explain to me what the correct model should be when using IQueryable or IEnumerable, that would be fine. However, after reading this link, it definitely seems like List is the way to go:
IEnumerable vs IQueryable for Business Logic or DAL return Types
The reason why your code failed when using IEnumerable/IQueryable is because the EF query is deferred; that is to say it doesn't actually get executed against the database until you start to enumerate (foreach, etc) or "materialise" (ToList(), etc) the results.
Therefore because you create an effectively temp DbContext with your using{}, the IEnumerable that you pass out of the function is a landmine - the underlying DbContext ceases to exist after the using block, and any attempt to enumerate or materialise the collection will fail.
Even when you created the DBContext without a using block, you then went ahead and Dispose'd of it before you executed the query - hence getting the same error.
This is one of the main reasons for not returning IQueryable from a DAL/Repository - because the recipient cannot know if the underlying context that the query relies on has been closed before they try to consume the results. IEnumerable is much better (List<T> implements IEnumerable<T> of course) and IMHO List is even better because it forces you to return a fully materialised collection and makes it clear to the caller that the result is not connected to the database any more.
So the working version that you have is probably fine - create your context, execute the query and then immediately materialise it which executes the actual SQL and then disconnects the result set from the database. So that pattern will work fine for you.
However I would recommend looking at having things like DbContext injected for you using an IoC container such as Ninject as it frees you from having to worry about the lifecycle of your DbContexts.
Hope that helps.
As you already knows, your DbContext enables you to query your database and so it has to be alive when SQL requests are sent to your SGBD.
The key point here is to know exactly how IQueryable works :
The IQueryable interface inherits the IEnumerable interface so that
if it represents a query, the results of that query can be enumerated.
Enumeration causes the expression tree associated with an IQueryable
object to be executed. The definition of "executing an expression
tree" is specific to a query provider. For example, it may involve
translating the expression tree to an appropriate query language for
the underlying data source.
Which means that as long as your Linq query has not been enumerated (with .ToList() or foreach), no query is sent to the database. The execution is deferred!
In your first attempt, you're :
Calling the GetProjectDropDownList method
Returning an IEnumerable (which is a Ling query) without "enumerating" it
Disposing the DbContext
Enumerating your Linq query through new SelectList when your view is generated but... Your DbContext has already been disposed at that time.
The same applies for your second attempt, the DbContext is disposed a little bit later but also already disposed when the view is generated.
In your last attempt, everything works fine because your DbContextis still alive when you're enumerating your Linq query (with project.ToList();)
In my opinion, isolating your DbContext calls and instances into a Data Access Layer and returning Lists or simple disconnected objects is not a bad practice at all.

Moq - Simple Cache Test

I'm just starting with Moq and unit testing in general. What I'm trying to do here is create a simple test to make sure my caching functionality is working correctly.
Why does the following test fail? The test is failing because the repository is getting called twice. However, I have stepped through the debugger and verified that the second call does pull from the cache and does not query the repository.
[TestMethod]
public void Test_Cache()
{
var Service = new Service(_mockRepository.Object, _mockLogger.Object, _mockCacheStorage.Object);
Service.GetAll();
Service.GetAll();
_mockRepository.Verify(r => r.FindAll(), Times.Once());
}
Update
Here is the service code, which I have verified works through the debugger.
public IList<Csa> GetAll()
{
try
{
string cacheKey = "GetAll";
IList<Csa> activeList = _cacheStorage.Get<List<Csa>>(cacheKey);
if (activeList == null)
{
activeList = _Repository.FindAll();
_cacheStorage.Set(cacheKey, activeList);
}
return activeList;
}
catch (Exception exception)
{
_logger.Log(LogType.Error, exception.ToString());
throw;
}
}
I think you need to break up your testing into two seperate tests. One test should verify that the Repository is accessed when the activeList is null, and the other test should verify that the fetch from the repository is skipped when the activeList is not null. The key is to 'stub' the _cacheStorage.Get<> call in the skipped version.
Something like this:
[TestMethod]
public void Test_Cache()
{
var Service = new Service(_mockRepository.Object, _mockLogger.Object, _mockCacheStorage.Object);
_mockCacheStorage.SetupGet(g => g.Get<List<Csa>>(It.IsAny<string>).Returns(new List<Csa>());
Service.GetAll();
_mockRepository.Verify(r => r.FindAll(), Times.Never());
}
It appears you have a problem with your mock cache storage always returning null. You are mocking the cache storage, so my guess is that calls to Get and Set on your cached storage aren't saving off the list properly. You have a few options:
mock get and set on your mock cache storage to get and set a local variable or dictonary
create a stub implementation of your cache storage interface that just uses a dictionary underneath
don't inject a dependency for your cache storage and just use a dictionary in your implementation.

Categories