簡體   English   中英

應用程序層單元測試在DDD中的外觀如何?

[英]How does application layer unit tests look like in DDD?

在我的工作中,我們正在編寫由應用程序調用的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,這是域責任。 因此,問題是:應用程序層單元測試應該看起來如何,應該測試什么? 我讀過某個地方,單元測試應該在“用於流控制的應用程序服務和用於業務規則的域模型”中進行測試。 有人可以詳細說明並舉例說明應測試什么樣的應用程序層單元測試嗎?

應用服務單元測試

應用程序服務的職責包括輸入驗證,安全性和事務控制。 所以這是您應該測試的!

以下是應用服務單元測試應提供的一些示例問題,並回答:

我的應用程式服務...

  • 傳遞垃圾時行為正確(例如返回預期的錯誤)?
  • 只允許管理員訪問它?
  • 在成功案例中正確提交交易?

根據您實現這些方面的精確程度,測試它們可能有意義也可能沒有意義。 例如,安全性通常以聲明性的方式實現(例如,具有C#屬性)。 在這種情況下,您可能會發現一種代碼審查方法比通過單元測試檢查每個應用程序服務的安全屬性更合適。 但是YMMV。

另外,請確保您的單元測試是實際的單元測試,即對所有內容(尤其是域對象)進行存根或模擬。 在測試中尚不清楚是這種情況(請參見下面的旁注)。

一般應用服務的測試策略

對應用程序服務進行單元測試是一件好事。 但是,在應用程序服務級別上,從長遠來看,我發現集成測試更有價值。 因此,我通常建議以下組合策略來測試應用程序服務:

  1. 為好的情況和壞的情況創建單元測試(如果需要,可以使用TDD樣式)。 輸入驗證很重要,因此請不要跳過不良情況。
  2. 為好的情況創建一個集成測試。
  3. 如果需要,請創建其他集成測試。

邊注

您的單元測試包含一些代碼氣味。

例如,我總是在單元測試中直接實例化SUT(被測系統)。 這樣,您便確切知道它具有哪些依賴項,並且對其中的哪些項進行了存根,模擬或使用了真正的依賴項。 在您的測試中,這一點還不清楚。

另外,您似乎依賴於字段來收集測試輸出(例如this._balances )。 如果測試類僅包含一個測試,通常這不是問題,但否則可能會出現問題。 通過依賴字段,您可以依賴測試方法“外部”的狀態。 這可能會使測試方法難以理解,因為您不能只是通讀測試方法,而是需要考慮整個類。 這是過度使用設置和拆卸方法時發生的相同問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM