In my job we are writing web services, which are called by an app. We are working in agile mind set using domain driven design. As in DDD we have domain and application layer. However, we encountered problem in writing unit tests for those layers, because it seems that we are testing domain logic twice: in domain unit tests and again in application unit tests:
Application unit test
[TestMethod]
public void UserApplicationService_SignOut_ForExistingUserWithBalance_ShouldClearBalanceAndSignOut()
{
//Arrange
long merchantId = 1;
long userId = 1;
var transactionId = "001";
var id = "122";
var user = Help.SetId<User>(User.Register(id, new DateTime(2015, 01, 01, 00, 00, 01)), userId);
_usersDb.Add(user);
var userBonusBalanceRepository = _testContext.MoqUnitOfWork.MockUnitOfWork.Object.GetUserBonusAccountRepository();
UserBonusAccount uba = userBonusBalanceRepository.GetForUser(user);
uba.PayTo(
new Domain.Core.Money { TotalAmount = 10, BonusAmount = 0 },
new Domain.Core.Outlet
{
BonusPercentage = 50,
IsLoyalty = true,
Id = id,
OutletId = "111"
},
transactionId,
DateTime.Now);
userBonusBalanceRepository.Update(uba);
//Act
_testContext.UserApplicationService.SignOut(id);
//Assert
var firstOrDefault = this._balances.FirstOrDefault(x => x.UserId == user.Id && x.MerchantId == merchantId);
Assert.IsTrue(firstOrDefault != null && firstOrDefault.Balance == 0);
Assert.IsNotNull(this._transactions.Where(x => x.Id == transactionId && x.Type == BonusTransactionType.EraseFunds));
}
Domain unit test
[TestMethod]
public void UserBonusAccount_ClearBalances_shouldClearBalancesForAllMerchants()
{
long userId = 1;
long firstMerchantId = 1;
long secondMerchantId = 2;
User user = User.Register("111", new DateTime(2015, 01, 01, 00, 00, 01));
Shared.Help.SetId(user, userId);
List<BonusTransaction> transactions = new List<BonusTransaction>();
List<BonusBalance> balances = new List<BonusBalance>();
var userBonusAccount = UserBonusAccount.Load(transactions.AsQueryable(), balances.AsQueryable(), user);
userBonusAccount.PayTo(new Money {TotalAmount = 100, BonusAmount = 0},
new Outlet
{
BonusPercentage = 10,
IsLoyalty = true,
MerchantId = firstMerchantId,
OutletId = "4512345678"
}, "001", DateTime.Now);
userBonusAccount.PayTo(new Money {TotalAmount = 200, BonusAmount = 0},
new Outlet
{
BonusPercentage = 10,
IsLoyalty = true,
MerchantId = secondMerchantId,
OutletId = "4512345679"
}, "002", DateTime.Now);
userBonusAccount.ClearBalances();
Assert.IsTrue(userBonusAccount.GetBalanceAt(firstMerchantId) == 0);
Assert.IsTrue(userBonusAccount.GetBalanceAt(secondMerchantId) == 0);
}
As you can see these both tests checks whether user balance is 0, which is domain responsibility. Thus the question is: how application layer unit tests should look like and what it should test? Somewhere I read that unit tests should test in "application services for flow control and domain models for business rules". Could someone elaborate more and give some examples what application layer unit tests should test and look like?
The application layer Application Layer: Defines the jobs the software is supposed to do and directs the expressive domain objects to work out problems. The tasks this layer is responsible for are meaningful to the business or necessary for interaction with the application layers of other systems.
To diagnose DDD, you may need to have some imaging tests. You may have an x-ray, which can help your surgeon "see" the bones in your spine. X-rays are effective at showing narrowed spinal channels (spinal stenosis), fractures, bone spurs (osteophytes), or osteoarthritis.
Unit testing is a software development process in which the smallest testable parts of an application, called units, are individually and independently scrutinized for proper operation. This testing methodology is done during the development process by the software developers and sometimes QA staff.
It is a good practice to write unit test for every layer, even the DAL.
The responsibilities of app services include input validation, security and transaction control. So this is what you should test!
Here are some example questions that app service unit tests should provide and answer for:
Does my app service...
Depending on how exactly you implement these aspects it may or may not make sense to test them. Security, for example, is often implemented in a declarative style (e.g. with C# attributes). In that case you may find a code review approach more appropriate than checking the security attributes of each and every app service with a unit test. But YMMV.
Also, make sure your unit tests are actual unit tests, i.e. stub or mock everything (especially domain objects). It's not clear in your test that this is the case (see side note below).
Having unit tests for app services is a good thing. However, on the app service level, I find integration tests to be more valuable in the long run. So I typically suggest the following combined strategy for testing app services:
Your unit tests contain a few code smells.
For example, I always instantiate the SUT (system under test) directly in unit tests. Like that, you exactly know what dependencies it has, and which of them are stubbed, mocked, or the real one is used. In your tests, this is not at all clear.
Also, you seem to depend on fields for collecting the test output (this._balances
for example). While this is usually not a problem if the test class contains only a single test, it can be problematic otherwise. By depending on fields, you depend on state that is "external" to the test method. This can make the test method difficult to understand, because you can't just read through the test method, you need to consider the whole class. This is the same problem that occurs when over-using setup and tear-down methods.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With