2017-07-31 21 views
1

我需要你的幫助,以便找到一種方法來驗證嵌套對象的值作爲被測試方法調用的參數傳遞。 假設這個類:FakeItEasy - 如何驗證嵌套參數值C#

public class AuditTrailValueObject 
{ 
    public ActionType Action { get; private set; } 
    public EntityType EntityType { get; private set; } 
    public long EntityId { get; private set; } 
    public DateTime StartTime { get; private set; } 
    public bool IsSuccess { get; private set; } 
    public string Remarks { get; private set; } 

    public AuditTrailValueObject(ActionType action, EntityType entityType, long entityId, DateTime startTime, bool isSuccess, string remarks = "") 
    { 
     Action = action; 
     EntityType = entityType; 
     EntityId = entityId; 
     StartTime = startTime; 
     IsSuccess = isSuccess; 
     Remarks = remarks; 
    } 
} 

而下面的接口有這個類作爲注入依賴性:

public interface IAuditTrailService 
{ 
    void WriteToAuditTrail(AuditTrailValueObject auditParamData); 
} 

現在我必須取決於AuditTrailServiceScanService(實現IAuditTrailService):

public long CreateScanRequest(long projectId) 
{ 
    ScanRequestWriteModel scanRequest = _scanRequestWriteModelFactory.Create(projectDetails); 

    long scanRequestId = _scanRequestsWriteRepository.Insert(scanRequest); 

    _auditTrailService.WriteToAuditTrail(new AuditTrailValueObject(ActionType.Run, EntityType.SastScanRequest, scanRequestId, DateTime.UtcNow, true)); 

    return scanRequestId; 
} 

我寫的測試:

[TestMethod] 
public void Scan_GivenProjectId_ShouldAuditSuccess() 
{ 
    //Given 
    var projectId = 100; 

    var scanService = CreateScanService(); 

    ... 
    A.CallTo(() => _scanRequestWriteModelFactory.Create(projectDetails)).Returns(new ScanRequestWriteModel()); 
    A.CallTo(() => _scanRequestsWriteRepository.Insert(A<ScanRequestWriteModel>._)).Returns(1); 

    //When 
    var scanRequestId = scanService.CreateScanRequest(projectId); 

    //Then 
    A.CallTo(() => _auditTrailService.WriteToAuditTrail(
         new AuditTrailValueObject(ActionType.Run, EntityType.SastScanRequest, scanRequestId, A<DateTime>._, true, A<string>._))).MustHaveHappened(); 
} 

當運行這個測試我越來越:

System.InvalidCastException:指定的轉換無效

我如何驗證AuditTrailValueObject嵌套參數的值?

+0

你能告訴我們錯誤發生的地方嗎?你有沒有堆棧跟蹤?任何會縮小這個範圍的東西?在這個問題中你已經拋棄了很多代碼。也許請參考https://stackoverflow.com/help/how-to-ask並重新解釋一下這個問題。 我_did_採取所有的代碼,並嘗試重現。我有一些問題,因爲有很多位被遺漏了,我不得不猜測。此外,您的測試不會編譯:我認爲你有一個重複「A.CallTo((=)_auditTrailService.WriteToAuditTrail(」行。 如果你更正這些問題並提供完整的測試輸出,我會再試一次 –

+0

@ BlairConrad我已經修復了你注意到的錯誤行,你願意我會上傳所有錯過的行嗎(可能會更累人......) – Roni

+0

我認爲最好的方法就是指出無效行爲的來源。 '請注意例外情況,包括整個堆棧跟蹤例外 (考慮到你已經包含的代碼量,更多的代碼並沒有那麼糟糕,我認爲要麼刪除多餘的代碼直到你有一個非常集中的例子,或包括足夠的編譯和運行。) –

回答

2

@湯姆·雷德芬使得許多好點,你可能想要解決這個問題。但是在重新閱讀你的代碼和評論之後,我想我是一個直接的前進方向。你的代碼至少有一個問題,它可能有另一個問題。

讓我們看看

A.CallTo(() => _auditTrailService.WriteToAuditTrail(
         new AuditTrailValueObject(ActionType.Run, 
                EntityType.SastScanRequest, 
                scanRequestId, 
                A<DateTime>._, 
                true 
                A<string>._))) 
     .MustHaveHappened(); 

_結構正在這裏使用的AuditTrailValueObject構造函數中,它們是無效的存在。他們將導致默認值被分配給AuditTrailValueObject,(DateTime.MinValue和null,我認爲),並且幾乎不是你想要的。如果您將new解壓到上一行,則會在使用_時看到FakeItEasy引發錯誤。我認爲它應該會更好地幫助您在代碼中找到問題,但我不確定這是否可行。我創建了FakeItEasy Issue 1177 - Argument constraint That, when nested deeper in A.CallTo, misreports what's being matched以幫助FakeItEasy改進。

與此相關的是FakeItEasy如何與物體相匹配。當提供一個值進行比較時,(new AuditTrailValueObject(…)的結果)FakeItEasy將使用Equals來比較對象與接收到的參數。除非您的AuditTrailValueObject有很好的Equals,否則會失敗。

如果您想繼續使用AuditTrailValueObject並且不想提供Equals(這會忽略startTime和備註),那麼可以繼續前進。

首先,你可以使用That.Matches,就像這樣:

A.CallTo(() => _auditTrailService.WriteToAuditTrail(A<AuditTrailValueObject>.That.Matches(
                 a => a.Action == ActionType.Run && 
                 a.EntityType == EntityType.SastScanRequest && 
                 a.EntityId == scanRequestId && 
                 a.IsSuccess))) 
                .MustHaveHappened(); 

有些人是不是野生的Matches複雜的約束,那麼還有一個辦法是捕捉AuditTrailValueObject後來詢問它,因爲亞歷克斯·詹姆斯布朗在他的回答中描述了Why can't I capture a FakeItEasy expectation in a variable?

2

你的問題是一個更大問題的症狀:你試圖做太多的一個測試。

因爲您正在創建WriteToAuditTrail()方法中的AuditTrailValueObject實例,所以您無法訪問此對象實例,因爲它在方法範圍內創建,因此不受檢查影響。

但是,看起來您希望首先訪問此對象的唯一原因是您可以驗證在其中設置的值是否正確。

這些值中,只有一個(就您的代碼示例而言,我們可以知道)從調用方法中設置。這是對_scanRequestsWriteRepository.Insert()的調用的返回值,它應該是它自己的單元測試的主題,您可以在其中獨立驗證正確的行爲,而不管它在何處使用。

編寫此單元測試(在_scanRequestsWriteRepository.Insert()方法中)實際上會解決您的問題的根本原因(您在單個測試中做得太多)。但是,您的直接問題仍然需要解決。這樣做的最簡單方法是完全刪除AuditTrailValueObject類,並直接將您的參數傳遞給對WriteToAuditTrail()的調用。

如果我將刪除AuditTrailValueObject,在那裏我應該驗證 什麼params被傳遞給auditTrailService?我的意思是 ,如果我已經測試了auditTrailService,我需要知道 如果使用正確的參數掃描服務調用(例如:使用 ActionType.Run而不使用ActionType.Update)。

要驗證正確的參數已經傳遞到調用WriteToAuditTrail()你可以注入IAuditTrailService的假冒驗證您的電話已經發生:

A.CallTo(
    () => _auditTrailService.WriteToAuditTrail(
        ActionType.Run, 
        EntityType.SastScanRequest, 
        scanRequestId, 
        myDateTime, 
        true, 
        myString) 
).MustHaveHappened(); 
+0

@tomredffern從概念上講,我同意你的看法。我不確定我完全理解你的意思。我想驗證的值是'AuditTrailValueObject'字段,例如'ActionType.Run','EntityType.SastScanRequest'。這些值不是來自'_scanRequestsWriteRepository.Insert()'調用的返回對象的一部分。所以我的問題是,如果我不會使用這些更改,那麼我建議如何驗證這些值? – Roni

+0

@Roni - 我知道你試圖驗證哪些值。但是,我說這不是做這種驗證的地方。驗證這些值的地方是在它們被創建的地方,而不是在它們被使用時。另外,我在說你可以進一步去掉AuditTrailValueObject對象。我在代碼中沒有看到它存在的原因。你不需要它 - 除了商店價值之外,它什麼也不做。 –

+0

如果我將刪除'AuditTrailValueObject',我應該在哪裏驗證哪些參數正在傳遞給'auditTrailService'?我的意思是,如果我已經測試了'auditTrailService',如果使用正確的參數(例如:使用'ActionType.Run'而不使用'ActionType.Update'),我需要知道掃描服務調用。謝謝! – Roni