Tôi đã phải vật lộn với một vấn đề ngày càng khó chịu liên quan đến các bài kiểm tra đơn vị của chúng tôi mà chúng tôi đang thực hiện trong nhóm của mình. Chúng tôi đang cố gắng thêm các bài kiểm tra đơn vị vào mã kế thừa không được thiết kế tốt và trong khi chúng tôi không gặp khó khăn gì với việc bổ sung thực tế các bài kiểm tra mà chúng tôi đang bắt đầu đấu tranh với cách các bài kiểm tra được thực hiện.
Như một ví dụ về vấn đề, giả sử bạn có một phương thức gọi 5 phương thức khác là một phần của việc thực thi. Một thử nghiệm cho phương pháp này có thể là để xác nhận rằng một hành vi xảy ra là kết quả của một trong 5 phương thức khác được gọi này. Vì vậy, vì một bài kiểm tra đơn vị nên thất bại chỉ vì một lý do và một lý do duy nhất, bạn muốn loại bỏ các vấn đề tiềm ẩn gây ra bằng cách gọi 4 phương thức khác này và chế nhạo chúng. Tuyệt quá! Thử nghiệm đơn vị thực thi, các phương thức giả định bị bỏ qua (và hành vi của chúng có thể được xác nhận là một phần của các thử nghiệm đơn vị khác) và xác minh hoạt động.
Nhưng có một vấn đề mới - bài kiểm tra đơn vị có kiến thức sâu sắc về cách bạn xác nhận hành vi đó và bất kỳ chữ ký nào thay đổi đối với bất kỳ phương thức nào trong 4 phương pháp khác trong tương lai hoặc bất kỳ phương pháp mới nào cần được thêm vào 'phương thức cha mẹ', sẽ dẫn đến việc phải thay đổi bài kiểm tra đơn vị để tránh những thất bại có thể xảy ra.
Đương nhiên, vấn đề có thể được giảm bớt phần nào bằng cách đơn giản là có nhiều phương pháp thực hiện ít hành vi hơn nhưng tôi đã hy vọng có lẽ có một giải pháp thanh lịch hơn.
Đây là một bài kiểm tra đơn vị mẫu để nắm bắt vấn đề.
Như một lưu ý nhanh 'MergeTests' là lớp kiểm tra đơn vị kế thừa từ lớp chúng tôi đang kiểm tra và ghi đè hành vi khi cần. Đây là một "mẫu" mà chúng tôi sử dụng trong các thử nghiệm của mình để cho phép chúng tôi ghi đè các cuộc gọi đến các lớp / phụ thuộc bên ngoài.
[TestMethod]
public void VerifyMergeStopsSpinner()
{
var mockViewModel = new Mock<MergeTests> { CallBase = true };
var mockMergeInfo = new MergeInfo(Mock.Of<IClaim>(), Mock.Of<IClaim>(), It.IsAny<bool>());
mockViewModel.Setup(m => m.ClaimView).Returns(Mock.Of<IClaimView>);
mockViewModel.Setup(
m =>
m.TryMergeClaims(It.IsAny<Func<bool>>(), It.IsAny<IClaim>(), It.IsAny<IClaim>(), It.IsAny<bool>(),
It.IsAny<bool>()));
mockViewModel.Setup(m => m.GetSourceClaimAndTargetClaimByMergeState(It.IsAny<MergeState>())).Returns(mockMergeInfo);
mockViewModel.Setup(m => m.SwitchToOverviewTab());
mockViewModel.Setup(m => m.IncrementSaveRequiredNotification());
mockViewModel.Setup(m => m.OnValidateAndSaveAll(It.IsAny<object>()));
mockViewModel.Setup(m => m.ProcessPendingActions(It.IsAny<string>()));
mockViewModel.Object.OnMerge(It.IsAny<MergeState>());
mockViewModel.Verify(mvm => mvm.StopSpinner(), Times.Once());
}
Làm thế nào phần còn lại của bạn xử lý vấn đề này hoặc không có cách xử lý 'đơn giản' tuyệt vời?
Cập nhật - Tôi đánh giá cao phản hồi của mọi người. Thật không may, và thực sự không có gì đáng ngạc nhiên, dường như không có một giải pháp, mô hình hay thực tiễn tuyệt vời nào mà người ta có thể làm theo trong kiểm thử đơn vị nếu mã được kiểm tra kém. Tôi đã đánh dấu câu trả lời tốt nhất nắm bắt sự thật đơn giản này.