Integration test good practice - c#

I am using unit test for some time. But now I need to write integration test. I should save something to DB, and than check if saved data is ok.
I can't find simple clean example of integration test.
My idea is to do like this:
[Test]
public void IntegrationTestExample()
{
// Arrange without mocking
var objec1 = new objec1();
var objec2 = new objec2();
var startTestClass = new startTestClass(objec1, objec2);
var saveData = "test data";
//Act
startTestClass.SaveToDB(saveData);
// Assert
var valueFromDB = SelectSavedData();
Assert.AreEqual(saveData, valueFromDB);
}
//Get data from DB for assert
private string SelectSavedData()
{
var sqlQuery = "Select TOP 1 data from table1";
var data = RepositoryForTest.selectSavedData(sqlQuery);
return data;
}
But I am not sure if this is good approach?
Do you have any suggestions?

You should test one piece of integration at a time, and leave the DB in such a state that it can run multiple tests and they should not affect each other. The MS test framework allows you to define methods that will setup and cleanup the tests at certain times during the test run, as shown in the following code
[TestClass]
public class ReturnServiceTest {
[ClassInitialize()]
public static void ClassInit(TestContext context) {
//INIT TEST DATA FOR THE CLASS
}
[TestCleanup]
public void TestCleanup() {
//CLEANUP DATA AFTER EACH TEST
}
[TestMethod]
public void IntegrationTestExample() {
// Arrange without mocking
var objec1 = new objec1();
var objec2 = new objec2();
var startTestClass = new startTestClass(objec1, objec2);
var saveData = "test data";
//Act
startTestClass.SaveToDB(saveData);
// Assert
var valueFromDB = SelectSavedData();
Assert.AreEqual(saveData, valueFromDB);
}
//Get data from DB for assert
private string SelectSavedData() {
var sqlQuery = "Select TOP 1 data from table1";
var data = RepositoryForTest.selectSavedData(sqlQuery);
return data;
}
}

When you are using a real database you should clean it up after each test attempt.
How you access the data is also not very clear, what proves, that RepositoryForTest does not contain any errors? Try to do the simplest thing that is possible for your assertion.
My Tests against databases look like:
public void Test()
{
try
{
// Fixture setup
// Create and insert data into Database (with plain ADO code)
// Exercise system
// Verify outcome
// use your data layer here
}
finally
{
// Teardown - other methods to clean the tables afterwards
DatabaseHelper.ClearLookups();
DatabaseHelper.ClearBeds();
...
}
}

Related

Unit test result in null object while testing a web api 2

I am new to MS Unit Testing and Moq objects. I am trying to test my Web API 2 controller. I have given below my unit test and controller code. While stepping through the code, it doesn't even go to the GetDeliveryCodeStrategy method.
[TestMethod]
public void CreateDelivery_ShouldReturnDeliveryCode()
{
Mock<IDeliveryStrategy> deliveryStrategy = new Mock<IDeliveryStrategy>
();
Mock<IDeliveryCode> deliveryCode = new Mock<IDeliveryCode>();
var controller = new DeliveryCodeController(deliveryStrategy.Object,
deliveryCode.Object);
var controllerContext = new HttpControllerContext();
var request = new HttpRequestMessage();
request.Headers.Add("appToken", "a57ffa87-950e-40f4-b965-17788becac7d");
controllerContext.Request = request;
controller.ControllerContext = controllerContext;
var result = controller.CreateDelivery(50) as
CreatedNegotiatedContentResult<IDeliveryCode>;
Assert.IsNotNull(result);
}
public class DeliveryCodeController : ApiController
{
IDeliveryStrategy _deliveryBatch;
IDeliveryCode _deliveryCode;
//Constructor dependency injection through Autofac
public DeliveryCodeController(IDeliveryStrategy DeliveryBatch,
IDeliveryCode deliveryCode)
{
_deliveryBatch = DeliveryBatch;
_deliveryCode = deliveryCode;
}
[HttpPost]
[Route("api/DeliveryCode/{percentage}")]
public IHttpActionResult CreateDelivery(int percentage)
{
String appToken = String.Empty;
if (Request.Headers.TryGetValues("appToken", out IEnumerable<String>
headerValues))
{
appToken = headerValues.FirstOrDefault();
}
if (!String.IsNullOrEmpty(appToken)))
{
IDeliveryContext deliveryContext =
_deliveryBatch.GetDeliveryCodeStrategy(percentage);
_deliveryCode.Code = deliveryContext.Create();
return Created(Request.RequestUri.ToString(), _deliveryCode);
}
else
{
return Content(HttpStatusCode.Forbidden, new Error { message = "The App
Token is not valid." });
}
}
}
When I do the "Debug Test" and step through the code, the deliveryContext
object comes as null in the code IDeliveryContext deliveryContext =
_deliveryBatch.GetDeliveryCodeStrategy(percentage);
You have to set up the Mock to return a certain value:
IDeliveryContext deliveryContext = // ???? - whatever you want it to be.
// Could be another Mock.
// This is what the Mock will return.
Mock<IDeliveryStrategy> deliveryStrategy = new Mock<IDeliveryStrategy>();
deliveryStrategy.Setup(x => x.GetDeliveryCodeStrategy(It.IsAny<decimal>()))
.Returns(deliveryContext);
This tells the Mock that that when its GetDeliveryCodeStrategy method is called, it should return the specified IDeliveryContext. Depending on what you're trying to do, that could be another Mock. (Mocks that return mocks are undesirable, but if you're starting out I'd file that detail away and come back to it.)
I'm guessing that percentage is a decimal. It.IsAny<decimal>() means that the mock doesn't care what the value is. That's usually okay because what you're testing is what your class does with the object returned by the mock.
You need to call Setup() on mock objects for the methods that you want to use:
var deliveryStrategy = new Mock<IDeliveryStrategy>();
deliveryStrategy.Setup(x => x.GetDeliveryCodeStrategy(It.IsAny<int>))
.Returns(AMockOfDeliveryContext); //you need to mock it beforehand so you can
//use the object here

Unit Testing a Basic c# application with repository

I have a basic .NET application that I am being asked to write a unit test for, but unit tests have always confused me.
This application has two repositories (FoodRepository and DrinkRepository) that return data from a hardcoded list.
Here's the Program.cs:
public static void Main(string[] args)
{
var foodSvc = new FoodService();
var foodId = 12;
var grade = 98.2d;
foodSvc.UpdateFoodGrade(foodId, grade);
}
which calls:
public void UpdateFoodGrade(int foodId, double grade)
{
var foodRepo = new FoodRepository();
var food = foodRepo.GetFood(foodId);
food.Grade = grade;
if (!food.IsPassed)
{
var drinkRepository = new DrinkRepository();
var drink = drinkRepository.GetDrink(foodId);
if (grade >= drink.MinimumPassingGrade)
{
food.IsPassed = true;
}
else
{
food.IsPassed = false;
}
}
}
My question is, what unit test(s) typically would someone do here for this? And, can I get some examples?
Been googling and grinding on this, but the concept continues to escape me.
I've historically used full integration tests in test environments, and not really done unit tests.
If anyone needs more of the code to help with this please let me know. I'm super stuck.
Thanks
UPDATE:
I've gotten a lot further thanks to below, but I am still stuck on the rest of the test. Here's what my updated service looks like:
public class FoodService
{
private readonly FoodRepository _foodRepo;
private readonly DrinkRepository _drinkRepository;
public FoodService(FoodRepository foodRepo, DrinkRepository drinkRepository)
{
_foodRepo = foodRepo;
_drinkRepository = drinkRepository;
}
public void UpdateFoodGrade(int foodId, double grade)
{
var food = _foodRepo.GetFood(foodId);
food.Grade = grade;
if (!food.IsPassed)
{
var drink = _drinkRepository.GetDrink(foodId);
if (grade >= drink.MinimumPassingGrade)
{
food.IsPassed = true;
}
else
{
food.IsPassed = false;
}
}
}
}
Updated Main:
public class Program
{
public static void Main(string[] args)
{
var foodRepository = new FoodRepository();
var drinkRepository = new DrinkRepository();
var foodSvc = new FoodService(foodRepository, drinkRepository);
var foodId = 12;
var grade = 98.2d;
foodSvc.UpdateFoodGrade(foodId, grade);
}
}
Test So far (I have no idea what to do next)
[TestMethod]
public void UpdateFoodGrade_Test()
{
//Arrange
var foodId = 12;
var grade = 98.2d;
var expected = true;
var food = new Food() { FoodId = foodId };
var drink = new Drink() { DrinkId = foodId };
var foodRepositoryMock = new Mock<FoodRepository>();
foodRepositoryMock.Setup(m => m.GetFood(foodId)).Returns(food).Verifiable();
var drinkRepositoryMock = new Mock<DrinkRepository>();
drinkRepositoryMock.Setup(m => m.GetDrink(foodId)).Returns(drink).Verifiable();
var foodService = new FoodService(foodRepositoryMock.Object, drinkRepositoryMock.Object);
//Act
var actual = foodService.UpdateFoodGrade(foodId, grade);
//Assert
foodRepositoryMock.Verify();
drinkRepositoryMock.Verify();
Assert.AreEqual(expected, actual);
}
}
EDIT 2:
I went ahead and refactored in the interfaces, etc. Here's how it shook out:
[TestMethod]
public void UpdateLessonGrade_IsPassingGrade()
{
//Arrange
var lessonId = 12;
var lesson = new Lesson() { LessonId = lessonId };
var module = new Module() { ModuleId = lessonId };
var lessonRepositoryMock = new Mock<ILessonRepository>();
lessonRepositoryMock.Setup(x => x.GetLesson(lessonId)).Returns(lesson);
var moduleRepositoryMock = new Mock<IModuleRepository>();
moduleRepositoryMock.Setup(x => x.GetModule(lessonId)).Returns(module);
var lessonService = new LessonService(lessonRepositoryMock.Object, moduleRepositoryMock.Object);
//Act
lessonService.UpdateLessonGrade(12, 98.2d);
//Assert
Assert.IsTrue(lesson.IsPassed); // assuming it should pass in this condition
Assert.AreEqual(98.2d, lesson.Grade); // expected Lesson Grade should be what you expected the grade to be after you call UpdateLessonGrade
}
I'm on a mobile device right now, I can try to update the answer later this weekend, but this should get you started.
Refactor your method to use instance variables instead of direct instantiation in the method. Add them as parameters to your constructor. In the main method create your repository instances and pass them to the service constructor.
Now you can use something like Moq or the in memory provider for entity framework.
As for what to test, basically test every piece of branching logic. At a minimum, each piece of an if statement and the else conditions. You should also test what happens when your repository objects don't find what you're looking for (e.g. returns null). Offhand, I'm counting at least six tests.
Update: Bravo! Looking at your updated code in the question, everything is on the right track.
In your test method, you'll want to add:
var foodService = new FoodService(foodRepositoryMock.Object, drinkRepositoryMock.Object);
That will initialize your service with the mock objects.
Then you'll want to call your service with test parameters like:
foodService.UpdateFoodGrade(12, 98.2d);
The last part is check your food object using asserts like:
Assert.IsTrue(food.IsPassed) // assuming it should pass in this condition
Assert.Equals(98.2d, food.Grade); // expectedFoodGrade should be what you expected the grade to be after you call UpdateFoodGrade
It looks like you'll also need to flesh out the instance of your Drink object a little bit more. You need to specify a value for MinimumPassingGrade since it's used to drive the decision logic in your if statement, for example, if you want the food.IsPassed = true to trigger, you would instantiate the drink object like so:
var drink = new Drink() { DrinkId = foodId, MinimumPassingGrade = 50.0d };
You would create test methods for each of the other various test cases, failed the minimum, when it's equal to the score, if you can't find the food in the food repo, or the drink in the drink repo, etc.
One other note, you only need to worry about Verifiable mocks when you need to know that a method was/wasn't called. For these tests, I probably wouldn't verify that methods were called (creates tighter coupling between your test and the implementation vs. the behavior). You'd want to verify that the methods were called only if something in your service code truly depends on knowing that it was called. e.g. if you're using Entity Framework and you wanted to make sure you didn't forget to call SaveChanges().
Indeed, such code can't be "normally" unit-tested without preliminary refactoring. But you still have one (bit dirty) option: Shims mechanism of MS Fakes Library.
It allows you to substitute any method or property of any type (including static, non-public and system) with any arbitrary code. In your case you may create a ShimsContext in you test method, and give some fake behavior for FoodRepository.GetFood() and DrinkRepository.GetDrink() methods, for example, empty body doing nothing. So, when your test runs, your stub code gonna be executed instead of the actual code of repository classes. So you will test only Service code without executing code of repositories.
You may check this article for quick introduction to the library.
And please keep in mind that Shims is not a way of good unit-testing, It is just a tool to deal with such non-testable code in case when you absolutely need to unit-test it somehow without changing the code itself.

.NET Core how to unit test service?

I have build a WebAPI and want to create a unit test project to have my services tested automatically.
The flow of my WebAPI is simple:
Controller (DI Service) -> Service (DI Repository) -> _repo CRUD
Suppose I have a service like:
public int Cancel(string id) //change status filed to 'n'
{
var item = _repo.Find(id);
item.status = "n";
_repo.Update(item);
return _repo.SaveChanges();
}
And I want to build a unit test, which just use InMemoryDatabase.
public void Cancel_StatusShouldBeN() //Testing Cancel() method of a service
{
_service.Insert(item);
int rs = _service.Cancel(item.Id);
Assert.Equal(1, rs);
item = _service.GetByid(item.Id);
Assert.Equal("n", item.status);
}
I've searched other related question, found that
You can't use dependency injections on test classes.
I just want to know if there is any other solution to achive my unit test idea?
When unit testing, you should just supply all the dependencies of the class you are testing explicitly. That is dependency injection; not having the service construct its dependencies on its own but making it rely on the outer component to provide them. When you are outside of a dependency injection container and inside a unit test where you are manually creating the class you are testing, it’s your responsibility to provide the dependencies.
In practice, this means that you either provide mocks or actual objects to the constructor. For example, you might want to provide a real logger but without a target, a real database context with a connected in-memory database, or some mocked service.
Let’s assume for this example, that the service you are testing looks like this:
public class ExampleService
{
public ExampleService(ILogger<ExampleService> logger,
MyDbContext databaseContext,
UtilityService utilityService)
{
// …
}
// …
}
So in order to test ExampleService, we need to provide those three objects. In this case, we will do the following for each:
ILogger<ExampleService> – we will use a real logger, without any attached target. So any call on the logger will work properly without us having to provide some mock, but we do not need to test the log output, so we do not need a real target
MyDbContext – Here, we’ll use the real database context with an attached in-memory database
UtilityService – For this, we will create a mock which just setups the utility method we need inside the methods we want to test.
So a unit test could look like this:
[Fact]
public async Task TestExampleMethod()
{
var logger = new LoggerFactory().CreateLogger<ExampleService>();
var dbOptionsBuilder = new DbContextOptionsBuilder().UseInMemoryDatabase();
// using Moq as the mocking library
var utilityServiceMock = new Mock<UtilityService>();
utilityServiceMock.Setup(u => u.GetRandomNumber()).Returns(4);
// arrange
using (var db = new MyDbContext(dbOptionsBuilder.Options))
{
// fix up some data
db.Set<Customer>().Add(new Customer()
{
Id = 2,
Name = "Foo bar"
});
await db.SaveChangesAsync();
}
using (var db = new MyDbContext(dbOptionsBuilder.Options))
{
// create the service
var service = new ExampleService(logger, db, utilityServiceMock.Object);
// act
var result = service.DoSomethingWithCustomer(2);
// assert
Assert.NotNull(result);
Assert.Equal(2, result.CustomerId);
Assert.Equal("Foo bar", result.CustomerName);
Assert.Equal(4, result.SomeRandomNumber);
}
}
In your specific Cancel case, you want to avoid using any methods of the service you are not currently testing. So if you want to test Cancel, the only method you should call from your service is Cancel. A test could look like this (just guessing the dependencies here):
[Fact]
public async Task Cancel_StatusShouldBeN()
{
var logger = new LoggerFactory().CreateLogger<ExampleService>();
var dbOptionsBuilder = new DbContextOptionsBuilder().UseInMemoryDatabase();
// arrange
using (var db = new MyDbContext(dbOptionsBuilder.Options))
{
// fix up some data
db.Set<SomeItem>().Add(new SomeItem()
{
Id = 5,
Status = "Not N"
});
await db.SaveChangesAsync();
}
using (var db = new MyDbContext(dbOptionsBuilder.Options))
{
// create the service
var service = new YourService(logger, db);
// act
var result = service.Cancel(5);
// assert
Assert.Equal(1, result);
}
using (var db = new MyDbContext(dbOptionsBuilder.Options))
{
var item = db.Set<SomeItem>().Find(5);
Assert.Equal(5, item.Id);
Assert.Equal("n", item.Status);
}
}
Btw. note that I’m opening up a new database context all the time in order to avoid getting results from the cached entities. By opening a new context, I can verify that the changes actually made it into the database completely.

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.

Invocation was not performed on the mock, what could be wrong here?

this error is trown by the following TEST. If i test the DataLayer, the database gets updated and everything works. however the mock keeps sending out this error. i have a similar test that does work with almost the exact code (on the InsertRPAData). the only diffrence i can see is that the XMLDataEntity is a diffrent entity in the test compared to the Verify but both of them use the barcode = 1 though.
this test needs to be worked on and the XMLDataEntity is just there to allow me to verefy the Test. also ignore the return for now.
[TestInitialize]
public void TestInitialize()
{
_mockRepository = new Mock<IRPADataLayer>();
UnityUtil.UnityContainer = new UnityContainer();
UnityUtil.UnityContainer.RegisterInstance(typeof(IRPADataLayer), _mockRepository.Object);
}
[TestMethod]
public void TestDoSuppressions()
{
//Arange
var suppressiontest = new Suppression();
//Import the XML File
XElement newElement = XElement.Parse(get090XML());
XDocument testdoc = new XDocument();
testdoc.Add(newElement);
String string2Stream = String.Concat("1");
Stream reader = new MemoryStream(ASCIIEncoding.Default.GetBytes(string2Stream));
RPADataEntity rpa = new RPADataEntity();
XMLDataEntity test = new XMLDataEntity();
test.barcode = 1;
rpa.RPAID = 1;
rpa.XMLData = testdoc;
//Act
Int32 success = suppressiontest.DoSuppressions(reader, rpa);
//Assert
_mockRepository.Verify(x => x.UploadPreprocData(rpa, test));
}
The method being called is this one.
public Int32 DoSuppressions(Stream reader, RPADataEntity rpa)
{
XMLDataEntity test = new XMLDataEntity();
test.barcode = 1;
_IRPADataLayer.UploadPreprocData(rpa, test);
return 1;
}
and the interface is this
public interface IRPADataLayer
{
void InsertPreProcData(PreProcDataEntity PreProcDataEntity);
void InsertRpaData(RPADataEntity RPADataEntity);
RPATypeEntity GetRPAType(String type);
void UploadPreprocData(RPADataEntity rpa, XMLDataEntity xml);
}
Your verify is expecting a certain instance of XMLDataEntity, (the one your instantiating in your test).
However the method that is being tested creates it's own XMLDataEntity and calls UploadPreprocData.
So the verification fails because the method hasn't been called with the expected instance of XMLDataEntity.
Most mocking frameworks provide a way to to specify that the expected parameter can be of any instance, so that might be what your wanting here.
Hope that helps.
Edit:
In Moq, verifying and excepting any parameter of a given type is done by using:
It.IsAny<T>()
Where T is the type of the expected instance.
In your case this can be done like so:
_mockRepository.Verify(x => x.UploadPreprocData(rpa, It.IsAny<XMLDataEntity>()));

Categories