2016-03-02 52 views
0

我已經編寫了一個測試來驗證一小段新的功能,它調用一個大型的中間件函數,其中大量的邏輯將一種類型的用戶(一個ASP網絡成員用戶)轉換爲內部一個(SystemUser)。這是一個混亂的系統,但我不能把它撕掉,因此新的測試。Moq枚舉首先或默認消失

我的測試調用了一個GetAllActiveUsers()方法,該方法調用了幾個層,最終得到一個導致問題的枚舉。測試有DataContext的Mock<localEntities> mockDb一個嘲笑了實體框架,該框架設置如下:

[SetUp] 
public void Setup() 
    { 
     var mockUserSet = new Mock<DbSet<User>>(); 

     this.mockDb = new Mock<localEntities>(); 
     this.mockMembershipService = new Mock<IMembershipService>(); 
     this.mockRoleService = new Mock<IRoleService>(); 
     this.mockUserAgreementRelation = new Mock<DbSet<UserAgreementRelation>>(); 

     this.testUsers = this.CreateSystemUsers(); 

     this.mockDb.Setup(m => m.User).Returns(mockUserSet.Object); 

     mockUserAgreementRelation.SetupAllProperties(); 

     var agreementRelations = this.testUsers.Select(u => new UserAgreementRelation() { AgentUserID = u.UserId, IsDeleted = null }); 

     mockUserAgreementRelation.As<IQueryable<UserAgreementRelation>>().Setup(ua => ua.GetEnumerator()).Returns(agreementRelations.GetEnumerator()); 
     this.mockDb.Setup(m => m.UserAgreementRelation).Returns(mockUserAgreementRelation.Object); 
    } 

在我的測試我設置了一些用戶和調入var testActiveUsers = testRepo.GetAllActiveUsers();它調用的問題行。

這裏是我困惑的地方。

測試通過使用此代碼:

var agreementRelations = databaseContext.UserAgreementRelation().ToList(); 

var userAgreementFromDB = agreementRelations 
      .FirstOrDefault(x => x.AgentUserID == ramsUser.UserId && (x.IsDeleted == null || !(bool)x.IsDeleted)); 

,但無法使用此代碼:

var userAgreementFromDB = databaseContext.UserAgreementRelation 
      .FirstOrDefault(x => x.AgentUserID == ramsUser.UserId && (x.IsDeleted == null || !(bool)x.IsDeleted)); 

此外,如果我調試,並通過代碼,我可以用在快速手錶嘲笑用戶協議關係一次。我第一次看到我正在測試的每個用戶的UserAgreementRelation。如果我再次運行該手錶,即使代碼尚未提前,枚舉也不會產生結果。我猜這與這個問題有關。然而,因爲我不知道爲什麼它發生了,我不能說它是如何引起這個問題的。

請記住,簡單的代碼(沒有ToList())是生產代碼。目前運行良好,但是我的測試失敗了。由於這是一個直接的數據庫調用,枚舉整個UserAgreementRelation表不是一個可行的解決方案。

對此提出建議?

回答

1

我不確定我是否會遇到問題,因爲您沒有詳細說明它是如何「失敗」的。但是,也許你應該改變部分:

.Setup(ua => ua.GetEnumerator()).Returns(agreementRelations.GetEnumerator()) 

到:

.Setup(ua => ua.GetEnumerator()).Returns(() => agreementRelations.GetEnumerator()) 

的原因是,如果你的代碼測試調用GetEnumerator()不止一次多,起訂量不應該把手伸到老「使用過」的枚舉器實例可能已經進展到最後並可能被處置。相反,Moq應該重新運行一個Func<>,我的箭頭() => agreementRelations.GetEnumerator(),以獲得一個尚未提前(MoveNext())或關閉(Dispose())的新調查員。


提問者通知我(在下面的評論),他還需要Setup屬性ProviderIQueryableExpression

+0

你是對的,那是我的代碼中的一個錯誤。我已更正它,現在可以多次查看枚舉的內容。但是,我仍然在FirstOrDefaultLinq語句中遇到了令人沮喪的「對象未設置爲對象的實例」錯誤。 – Necoras

+0

我將此標記爲答案,因爲它確實修復了消失的枚舉器。然而,我爲什麼測試失敗仍然處於虧損狀態。 – Necoras

+0

@Necoras你需要提供更多關於它失敗的細節。你從Moq得到一個例外嗎? 'userAgreementFromDB'是否爲空?請包括所有可能的細節。它會幫助人們看到你的問題來自哪裏。 –

0

我一直在使用這裏的東西,試試這個。

var userAgreementFromDB = databaseContext.UserAgreementRelation 
      .Where(x => x.AgentUserID == ramsUser.UserId && (x.IsDeleted == null || !(bool)x.IsDeleted)).FirstOrDefault(); 
+0

我相信這在功能上等同於我的代碼。無論如何,結果是相同的:該行上的空引用異常。 – Necoras

+0

是databaseContext.UserAgreementRelation一個IEnumerable?如果之前的ToList()工作正常,但IEnumerable上的相同邏輯正在拋出錯誤,那麼有意義的是,您嘗試對IEnumerable執行某些不允許的操作。似乎發現問題的方法是在databaseContext.UserAgreementRelation上創建一個foreach循環,然後嘗試在裏面應用您的檢查。 – Seano666

+1

請參閱我上面的意見。謝謝您的幫助。 – Necoras