在我的工作中,我们正在编写由应用程序调用的Web服务。我们正在使用域驱动设计进行敏捷思维设置。与在DDD中一样,我们有域和应用层。但是,我们在为这些层编写单元测试时遇到了问题,因为我们似乎正在测试域逻辑两次:在域单元测试中,再次在应用程序单元测试中:
申请单元测试
[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));
}
域单元测试
[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);
}
正如您所看到的,这两个测试都会检查用户余额是否为0,这是域责任。因此问题是:应用程序层单元测试应该如何以及它应该测试什么?在某处,我读到单元测试应该在“流程控制的应用程序服务和业务规则的域模型”中进行测试。有人可以详细说明并给出一些应用层单元测试应该测试和看起来像的例子吗?
答案 0 :(得分:6)
应用服务的职责包括输入验证,安全性和事务控制。所以这就是你应该测试的东西!
以下是应用服务单元测试应提供并回答的一些示例问题:
我的应用服务......
根据您实际执行这些方面的准确程度,测试它们可能有也可能没有意义。例如,安全性通常以声明式样式实现(例如,使用C#属性)。在这种情况下,您可能会发现代码审查方法比使用单元测试检查每个应用程序服务的安全属性更合适。但是YMMV。
另外,确保您的单元测试是实际的单元测试,即存根或模拟所有内容(尤其是域对象)。在您的测试中并不清楚是这种情况(见下面的旁注)。
对应用服务进行单元测试是一件好事。但是,在应用程序服务级别上,我发现集成测试从长远来看更有价值。因此,我通常会建议以下用于测试应用服务的组合策略:
您的单元测试包含一些代码味道。
例如,我总是在单元测试中直接实例化SUT(被测系统)。就像那样,你完全知道它有哪些依赖关系,以及哪些是存根,模拟或真实存在。在你的测试中,这一点都不清楚。
此外,您似乎依赖于收集测试输出的字段(例如this._balances
)。虽然如果测试类只包含一个测试,这通常不是问题,否则可能会有问题。依靠字段,你依赖于&#34;外部&#34;对测试方法。这可能使测试方法难以理解,因为您无法通读测试方法,您需要考虑整个类。这与过度使用设置和拆卸方法时出现的问题相同。