this is my first time writing unit test, and I just have a few questions. Im using in memory database to test my services and I'am wondering if I'm doing it correctly. My first question is do I need multiple assert on all of my service call? like do i need assert for InsertProduct? Second, Am I over testing this for using new instance of context on every service call?
[Fact]
public void ProductService_DeleteProduct_Test()
{
// arrange
var options = new DbContextOptionsBuilder<ApplicationDbContext>()
.UseInMemoryDatabase(databaseName: "ProductService_DeleteProduct_Test")
.Options;
var product = new Product() { Id = Guid.NewGuid(), Name = "Product"};
// act
// insert
using (var context = new ApplicationDbContext(options))
{
var service = new Service(context);
service.ProductService.InsertProduct(product);
}
// delete
using (var context = new ApplicationDbContext(options))
{
var service = new Service(context);
service.ProductService.DeleteProducts(new List<Guid> { product.Id });
}
// assert
using (var context = new ApplicationDbContext(options))
{
var service = new Service(context);
Assert.Equal(0, service.ProductService.GetAllProducts().Count);
}
}
I would make an objection on the structure of your test. Namely, you are using the service (production code) to prepare the underlying database. And you are also using the production code to make the assertion.
If any part of the production code is incorrect, this test will fail. However, this test is designed to assert that the delete feature is doing right.
Therefore, I would rewrite entire test in the following way:
[Fact]
public void ProductService_DeleteProduct_Test()
{
// arrange
var options = new DbContextOptionsBuilder<ApplicationDbContext>()
.UseInMemoryDatabase(databaseName: "ProductService_DeleteProduct_Test")
.Options;
var product = new Product() { Id = Guid.NewGuid(), Name = "Product"};
// Insert object using other means, i.e. direct INSERT statement
// act
using (var context = new ApplicationDbContext(options))
{
var service = new Service(context);
service.ProductService.DeleteProducts(new List<Guid> { product.Id });
}
// assert
// Execute SELECT COUNT(*) instruction to fetch previously existing row
Assert.Equal(0, rowsCount);
}
In this way, you will only touch production code in the acting part of the test. That is the part in which you are using the service object to delete an object from the database.
Subsequent assertion is done against a scalar value count which is fetched as the result of a raw SELECT statement executed directly on the storage.
Bottom line is that none of the parts of your test are now depending on correctness of the production code, except the DeleteProducts method which is in fact the method under test.
And, consequently, the answer to your question is that there is only one assertion to write in this test.
Answering your first question, I'd say no. Since this is a unit test and you're testing the delete specifically. I consider the insert part of the setup since you're getting the system into a state where you want to test the delete. To Zoran Horvat's point, if you can, put a row in the database via some means other than the service itself.
To answer your second question, it seems unnecessary to have three using blocks where you're new'ing up the service three times. I'd put the insert, delete, and assert in the same using, making use of one instance of the SUT, or service.
However, if you have multiple tests that all require there to be a row in the database, consider moving the insert into a SetUp method with the [SetUp] attribute that every test can call before hand. In that case, you'd be using multiple instances of the context.
Related
I've never used AutoMapper before, so I'm wondering what unit-tests I need to write for this specific line of code:
IEnumerable<UserDetail> userDetails =
this.mapper.Map<IEnumerable<Entities.User>, IEnumerable<UserDetail>>(users);
the line in question is in this method:
public IEnumerable<UserDetail> GetUserDetails()
{
var users = this.userData.GetUsers();
//question is about testing this line
IEnumerable<UserDetail> userDetails =
this.mapper.Map<IEnumerable<Entities.User>, IEnumerable<UserDetail>>(users);
return userDetails;
}
Currently the unit-test provides a mock list of Users to return from this.userData.GetUsers() and then verifies the output userDetails contains the same data in this.userData.GetUsers()
This first unit-tests looks like this:
[Test]
public async Task VerifyAutoMapperProfile()
{
//Assert
this.MapperConfig.AssertConfigurationIsValid();
}
[Test]
public async Task UserService_GetUsers_Returns_IEnumerableUserDetails()
{
//Arrange
IList<Entities.User> usersFromData = this.GetMockUsers();
Mock<IUserDataAccess> mockUserData = new Mock<IUserDataAccess>();
mockUserData
.Setup(d => d.GetUsers())
.Returns(usersFromData);
//this loads the same AutoMapper.Profile that the application uses
IMapper mapper = this.MapperConfig.CreateMapper();
var userService = new UserService(mockUserData.Object, mapper);
//Act
var userDetails = userService.GetUserDetails();
//Assert
userDetails.Should().BeAssignableTo<IEnumerable<UserDetail>>();
userDetails.Should().HaveCount(usersFromData.Count);
userDetails.Should().NotContainNulls();
userDetails.Should().OnlyHaveUniqueItems();
userDetails.Should().AllBeOfType<UserDetail>();
foreach (Entities.User user in usersFromData)
{
var userDetail = new UserDetail {FullName = user.FullName, Guid = user.Guid};
userDetails.Should().ContainEquivalentOf(userDetail);
}
}
So question is, should I add any coverage in this test for the line I've indicated, or should I be creating separate tests for that line? (I will be creating more unit-tests in general for this method - but my question is specifically asking about the IMapper.Map method. Do I need to cover failures/exceptions thrown by that method? Is it enough just to have this.MapperConfig.AssertConfigurationIsValid()?
In your GetUserDetails() method, you do 2 things. First is loading users, second is converting. So basically, your unit test just need to verify those 2 things. First is GetUsers() invoked or not? Second is Map() invoked or not? And 1 extra thing, if you load 10 users, you expect to get back 10 users (do NOT check the user properties).
WHY you don't need to check user properties? Because the mapping logic is not in your method, so you don't need to unit-test that.
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 can the following test be corrected to work?
[TestMethod()]
public void GetEmployeeProductivityTest()
{
var mockHR = new Mock<IRepository<Employee>>();
var mockCMS = new Mock<ICMS_Repository>();
mockCMS.Setup(repos => repos.FindEmployeeByUsername(It.IsAny<string>())).Verifiable();
Employee newEmp = new Employee();
newEmp.User_Name = "testName";
var service = new EmployeeService(mockHR.Object,mockCMS.Object);
var createResult = service.GetEmployeeByUserName(newEmp);
Assert.AreEqual(newEmp, createResult);
mockCMS.VerifyAll();
}
I get the following:
Assert.AreEqual failed. Expected:<Employee>. Actual:<(null)>.
As Requested this is the GetEmployeeByUserName() function being called:
public Employee GetEmployeeByUserName(Employee employee)
{
return _employeeRespository.Find().ByUserName(employee); <------(Using Strict: Gives me the following: All invocations on the mock must have a corresponding setup.)
}
Since you edited your question to show the behaviour of the GetEmployeeByUserName, it's now easy to explain why your test was failing.
mockCMS.Setup(repos => repos.FindEmployeeByUsername(It.IsAny<string>()))
Here you set up an expectation that the FindEmployeeByUsername(string) overload would be called, but then you go on to use the FindEmployeeByUsername(Employee) overload. Moq setups are for specific overloads so when the method is called the mocked service finds no matching setup. If there is no matching setup, the mock either returns the default value for the Employee type (null), or throws an exception, depending on which MockBehavior you chose.
In your updated test, you fixed this by setting up the overload that you actually use.
mockCMS.Setup(repos => repos.FindEmployeeByUsername(It.IsAny<Employee>()))
With simple methods like your GetEmployeeByUserName, mocking the dependencies and unit testing it can seem like a lot of overhead. What your test says is basically,
"when someone calls the GetEmployeeByUserName method on the EmployeeService,
the service should call the correct method on its repository"
Is this an important thing to assert? That's up to you to decide. As the complexity of your service methods increases, however, being able to isolate the dependencies and test their interactions will become more and more valuable.
You need to seed the FindEmployeeByUsername() Method of your mock:
mockCMS.Setup(repos => repos.FindEmployeeByUsername(It.IsAny<string>())).Returns(newEmp);
otherwise it wont return the expected object, while called within the EmployeeService.
Instead of using multiple repositories which I think was confusing. I simplified it and it works now! Except I'm still not sure how this helps me code better. What did I accomplish with this? (I'm new to Testing/Moq/Integration Tests...etc..) I would really like an answer...to this..
public void GetEmployeeUsername_Using_EmployeeClass()
{
var mockCMS = new Mock<ICMS_Repository>(MockBehavior.Strict);
Employee newEmp = new Employee();
newEmp.User_Name = "testName";
mockCMS.Setup(repos => repos.FindEmployeeByUsername(It.IsAny<Employee>())).Returns(newEmp);
var service = new EmployeeService(mockCMS.Object);
var createResult = service.GetEmployeeByUserName(newEmp);
Assert.AreEqual(newEmp, createResult);
}
I am developing Moq tests for various entities. I can setup create and delete tests fine, but not update - the entity in the repository does not change. I know this is due to the PersistAll doing nothing (probably due to a setup I am missing).
This is a sample of an insert persist setup (I am looking for an Update version):
agg.Setup(a => a.InsertOnPersist<Thingy>(model)).Callback(() => mockThingies.Add(model));
In addition, I also have this to link the List to being the repository:
agg.Setup(a => a.GetObjectStore<Artist>()).Returns(mockThingies.AsQueryable());
This is a sample of an update test I have:
public List<Thingy> mockThingies; //this is our repository
[TestInitialize]
public void SetupTests()
{
mockThingies= new List<Thingy>();
Thingy someThingy = new Thingy();
someThingy.Name = "MyName";
someThingy.ID = 1;
mockThingies.Add(someThingy);
}
[TestMethod]
public void CanEditExistingThingy()
{
Mock<BusinessExceptionBroadcaster> beb = new Mock<BusinessExceptionBroadcaster>();
Mock<IValidationEngine> valid = new Mock<IValidationEngine>();
Mock<IAggregate> agg = new Mock<IAggregate>();
agg.Setup(a => a.GetObjectStore<Thingy>()).Returns(mockThingies.AsQueryable());
ThingyRepository repo = new ThingyRepository (agg.Object);
ThingyService service = new ThingyService (repo, beb.Object, valid.Object);
Thingy newThingy = new Thingy();
newThingy.ID = 1; //same as old
newThingy.Name = "newname"; //new name
Assert.AreNotEqual(newThingy.Name,mockThingies[0].Name);
Assert.IsTrue(service.Update(newThingy));
Assert.AreEqual(newThingy.Name, mockThingies[0].Name); //FAILS HERE
}
This is the code to update:
public bool Update(Thingy entity)
{
Thingy existingThingy= _Thingy.FirstOrDefault(t=>t.ID == entity.ID);
if (existingThingy != null)
{
_Thingy.PersistAll();
return true;
}
else
{
//unimportant
}
}
return false;
}
Don't worry about testing whether the update call actually updates something. You'll just want to verify that your service calls the appropriate method on the repo to perform the update and persist. Testing the actual update is a little outside the scope of this one test.
As far as I can see, it can't work, because you're setting one Thingy with ID=1 in Setup, and then create other one with same ID in test. Although they share same ID, they are not same, so your changes can't be ever propagated to repository.
In fact, I think that it's a bug in your CUT code, because while you're testing ID match, you don't test that your repository knows something about entity you're updating. To add, I personally think that there's something wrong with your repository design if it allows such things.
If we were talking about EntityFramework I'd say you have to attach your entity to context.
How can I mole the DataContext that I'm using in a class to write messages to a table. I'd like to assert that the table LINQ is writing to has the expected count of messages. Here's what i have so far.
var context = new MJustTestingDataContext();
MyMessagewriter writer = new MyMessageWriter(context);
var messageList = new List<MIncmoingMessage>();
MTable<MIncomingMessage> messageTable = new MTable<MIncomingMessage>();
messageTable.Bind(messagesLinqList.AsQueryable());
If I use this code with xUnit in my class under test I'll get this exception
Microsoft.Moles.Framework.Moles.MoleNotImplementedException: DataContext.Dispose() was not moled.
What am I missing here and how to implement DataContext.Dispose() on the mole? I'm using moles standalone without Pex.
When you create a new Mole the default behavior for its methods and properties is to throw a MoleNotImplementedException whenever they are called.
To implement the mole you can do context.Dispose = () => {}; which means that nothing happens when the Dispose method gets called on the moled instance.
I reread the question and you probably are having a problem since Dispose is defined in a base class. To mole base method you need to do the following:
var context = new MJustTestingDataContext();
var baseContext = new MDataContext(context);
baseContext.Dispose = () => {};
You'll need to implement every property/method that gets called by the code under test or you can set the default behavior for the mole instance globally using the method BehaveAsDefaultValue. This way every method in the mole will do nothing and return the default value for it's return type if one exists instead of throwing a MoleNotImplementedException. However if you require this behavior it's better to use a stub than a mole.
I'm having trouble understanding what your test is doing. I had to do something similar yesterday, so I'll share my experience. First, it's important to understand that you don't need to use all the MoleTypes to test your code -- you just need to use Moles to redirect certain parts of your code to lambda expressions. Given a method that does this:
get a list of users to modify from the database
modify every user in the set
send the new set back to the database
I'd like to redirect 1 and 3 to not use the database. For instance, I can redirect the call to SubmitChanges (3) via this code:
bool hitSubmitChanges = false;
int changeCount = 0;
IList<object> updates = null;
// more code here...
// redirect DataContext.SubmitChanges() to a lambda to catch updates
MDataContext.AllInstances.SubmitChanges = (c) =>
{
changeCount = c.GetChangeSet().Updates.Count;
updates = c.GetChangeSet().Updates;
hitSubmitChanges = true;
};
That (and the call to get the users) would be the only Moletypes I'd use in the test. The rest of it would be normal. Then I can use assertions to check the values of changeCount, updates and hitSubmitChanges.