Tại sao tôi cần kiểm tra đơn vị để thử nghiệm phương pháp kho lưu trữ?


19

Tôi cần phải chơi quỷ ủng hộ câu hỏi này một chút vì tôi không thể bảo vệ nó tốt vì thiếu kinh nghiệm. Đây là thỏa thuận, tôi có khái niệm về sự khác biệt giữa thử nghiệm đơn vị và thử nghiệm tích hợp. Khi đặc biệt tập trung vào các phương thức kiên trì và kho lưu trữ, một bài kiểm tra đơn vị sẽ sử dụng một giả có thể thông qua một khung như Moq để khẳng định rằng một đơn đặt hàng được tìm kiếm đã được trả lại như mong đợi.

Giả sử tôi đã xây dựng bài kiểm tra đơn vị sau:

[TestMethod]
public void GetOrderByIDTest()
{
   //Uses Moq for dependency for getting order to make sure 
   //ID I set up in 'Arrange' is same one returned to test in 'Assertion'
}

Vì vậy, nếu tôi thiết lập OrderIdExpected = 5và đối tượng giả của tôi trở lại 5làm ID thì bài kiểm tra của tôi sẽ vượt qua. Tôi hiểu rồi. Đơn vị tôi đã kiểm tra mã để đảm bảo những gì mã của tôi trả về đối tượng và ID dự kiến ​​chứ không phải thứ gì khác.

Đối số tôi sẽ nhận được là:

"Tại sao không chỉ cần bỏ qua các bài kiểm tra đơn vị và làm các xét nghiệm hội nhập? Nó kiểm tra các thủ tục cơ sở dữ liệu được lưu trữ cùng mã của bạn đó là quan trọng. Nó có vẻ như quá nhiều công việc thêm để có đơn vị xét nghiệm và kiểm tra tích hợp khi cuối cùng tôi muốn biết nếu các cuộc gọi cơ sở dữ liệu và mã hoạt động. Tôi biết các bài kiểm tra mất nhiều thời gian hơn, nhưng chúng phải được chạy và kiểm tra bất kể vì vậy dường như vô nghĩa đối với tôi để có cả hai. Chỉ cần kiểm tra những gì quan trọng. "

Tôi có thể bảo vệ nó bằng một định nghĩa trong sách giáo khoa như: "Vâng đó là một bài kiểm tra tích hợp và chúng tôi cần kiểm tra mã riêng như một bài kiểm tra đơn vị và, yada, yada, yada ..." Đây là một trường hợp giải thích thực tiễn thuần túy so với thực tế là mất đi. Đôi khi tôi gặp phải điều này và nếu tôi không thể bảo vệ lý do đằng sau mã kiểm tra đơn vị mà cuối cùng phụ thuộc vào các phụ thuộc bên ngoài, thì tôi không thể tạo ra một trường hợp cho nó.

Bất kỳ trợ giúp về câu hỏi này được đánh giá rất cao, cảm ơn!


2
tôi nói hãy gửi thẳng đến kiểm tra người dùng ... dù sao họ cũng sẽ thay đổi các yêu cầu ...
nathan hayfield

+1 cho sự mỉa mai để giữ cho mọi thứ nhẹ nhàng theo thời gian
atconway

2
Câu trả lời đơn giản là mỗi phương pháp có thể có x số trường hợp cạnh (giả sử bạn muốn kiểm tra ID dương, ID bằng 0 và ID âm). Nếu bạn muốn kiểm tra một số chức năng sử dụng phương pháp này, bản thân nó có 3 trường hợp cạnh, bạn sẽ cần phải viết 9 trường hợp kiểm tra để kiểm tra từng tổ hợp các trường hợp cạnh. Bằng cách cách ly chúng, bạn chỉ cần viết 6. Ngoài ra, các bài kiểm tra cung cấp cho bạn một ý tưởng cụ thể hơn về lý do tại sao một cái gì đó bị phá vỡ. Có lẽ kho lưu trữ của bạn trả về null khi thất bại và ngoại lệ null được ném hàng trăm dòng xuống mã.
Rob

Tôi nghĩ rằng bạn đang quá khắt khe với định nghĩa của bạn về một bài kiểm tra "đơn vị". "Đơn vị công việc" cho lớp kho lưu trữ là gì?
Caleb

Và hãy chắc chắn rằng bạn đang xem xét điều này: nếu đơn vị của bạn kiểm tra tất cả mọi thứ bạn đang cố gắng kiểm tra, bạn thực sự đang thử nghiệm điều gì?
Caleb

Câu trả lời:


20

Kiểm tra đơn vị và kiểm tra tích hợp có mục đích khác nhau.

Kiểm tra đơn vị xác minh chức năng của mã của bạn ... rằng bạn sẽ nhận được những gì bạn mong đợi từ phương thức khi bạn gọi nó. Kiểm thử tích hợp kiểm tra cách mã hoạt động khi kết hợp với nhau như một hệ thống. Bạn sẽ không mong đợi các thử nghiệm đơn vị để đánh giá hành vi hệ thống, cũng như bạn sẽ không mong đợi các thử nghiệm tích hợp để xác minh các đầu ra cụ thể của một phương pháp cụ thể.

Kiểm tra đơn vị, khi được thực hiện chính xác, dễ thiết lập hơn so với kiểm tra tích hợp. Nếu bạn chỉ dựa vào kiểm tra tích hợp, thử nghiệm của bạn sẽ:

  1. Nhìn chung, khó viết hơn
  2. Giòn hơn, do tất cả các phụ thuộc cần thiết, và
  3. Cung cấp bảo hiểm ít mã hơn.

Điểm mấu chốt: Sử dụng kiểm tra tích hợp để xác minh rằng các kết nối giữa các đối tượng đang hoạt động đúng, nhưng trước tiên hãy dựa vào kiểm tra đơn vị để xác minh các yêu cầu chức năng.


Tất cả những gì đã nói, bạn có thể không cần thử nghiệm đơn vị cho các phương thức lưu trữ nhất định. Kiểm thử đơn vị không nên được thực hiện trên các phương pháp tầm thường ; nếu tất cả những gì bạn đang làm đều chuyển qua yêu cầu một đối tượng đến mã được tạo ORM và trả về kết quả, bạn không cần phải kiểm tra đơn vị đó, trong hầu hết các trường hợp; một bài kiểm tra tích hợp là đầy đủ.


Vâng cảm ơn bạn đã phản hồi nhanh chóng tôi đánh giá cao nó. Bài phê bình duy nhất của tôi về câu trả lời là nó rơi vào mối quan tâm của đoạn cuối cùng của tôi. Sự phản đối của tôi sẽ vẫn chỉ nghe những giải thích và định nghĩa trừu tượng chứ không phải lý luận sâu sắc hơn. Ví dụ: bạn có thể cung cấp lý do áp dụng cho trường hợp sử dụng của tôi để kiểm tra thủ tục / DB được lưu trữ liên quan đến mã của tôi không và tại sao các thử nghiệm đơn vị vẫn có giá trị liên quan đến trường hợp sử dụng cụ thể này?
atconway

1
Nếu SP chỉ trả về kết quả từ cơ sở dữ liệu, kiểm tra tích hợp có thể là đầy đủ. Nếu nó có logic không tầm thường trong đó, các bài kiểm tra đơn vị được chỉ định. Xem thêm stackoverflow.com/questions/1126614/...msdn.microsoft.com/en-us/library/aa833169(v=vs.100).aspx (SQL Server cụ thể).
Robert Harvey

12

Tôi đứng về phía những người thực dụng. Đừng kiểm tra mã của bạn hai lần.

Chúng tôi chỉ viết các bài kiểm tra tích hợp cho các kho lưu trữ của chúng tôi. Các thử nghiệm này chỉ phụ thuộc vào một thiết lập thử nghiệm đơn giản chạy trên cơ sở dữ liệu trong bộ nhớ. Tôi nghĩ rằng họ cung cấp mọi thứ mà một bài kiểm tra đơn vị làm, và nhiều hơn nữa.

  1. Họ có thể thay thế cho các bài kiểm tra đơn vị khi làm TDD. Mặc dù có một số bản tóm tắt mã kiểm tra để viết trước khi bạn có thể bắt đầu với mã thực, nhưng nó hoạt động rất tốt với cách tiếp cận đỏ / xanh / tái cấu trúc một khi mọi thứ đã được đặt đúng chỗ.
  2. Họ kiểm tra mã thực của kho lưu trữ - mã chứa trong các chuỗi SQL hoặc các lệnh ORM. Điều quan trọng hơn là phải xác minh rằng truy vấn là chính xác hơn là xác minh rằng bạn thực sự đã gửi một số chuỗi tới StatementExecutor.
  3. Họ là tuyệt vời như các bài kiểm tra hồi quy. Nếu họ thất bại, đó luôn là do một vấn đề thực sự, chẳng hạn như thay đổi lược đồ chưa được tính đến.
  4. Chúng không thể thiếu khi thay đổi lược đồ cơ sở dữ liệu. Bạn có thể tự tin rằng bạn đã không thay đổi lược đồ theo cách phá vỡ ứng dụng của bạn miễn là vượt qua bài kiểm tra. (Thử nghiệm đơn vị là vô ích trong trường hợp này, vì khi thủ tục được lưu trữ không còn tồn tại, thử nghiệm đơn vị vẫn sẽ vượt qua.)

Thực tế rất thực tế. Tôi đã trải nghiệm trường hợp cơ sở dữ liệu trong bộ nhớ thực sự hoạt động khác nhau (không phải về hiệu năng) với cơ sở dữ liệu thực của tôi, vì ORM hơi khác nhau. Hãy chăm sóc điều đó trong các bài kiểm tra tích hợp của bạn.
Marcel

1
@Marcel, tôi đã chạy vào đó. Tôi đã giải quyết nó bằng cách đôi khi chạy tất cả các thử nghiệm của tôi đối với một cơ sở dữ liệu thực sự.
Winston Ewert

4

Các thử nghiệm đơn vị cung cấp một mức độ mô đun mà các thử nghiệm tích hợp (theo thiết kế) không thể. Khi một hệ thống được tái cấu trúc hoặc tái cấu trúc, các thử nghiệm đơn vị (và điều này sẽ xảy ra) thường có thể được sử dụng lại, trong khi các thử nghiệm tích hợp thường phải được viết lại. Các bài kiểm tra tích hợp cố gắng thực hiện công việc của một thứ nên có trong bài kiểm tra đơn vị thường làm quá nhiều, điều này khiến chúng khó bảo trì.

Ngoài ra, bao gồm kiểm tra đơn vị có các lợi ích sau:

  1. Kiểm tra đơn vị cho phép bạn nhanh chóng phân tách thử nghiệm tích hợp không thành công (có thể do lỗi hồi quy) và xác định nguyên nhân. Hơn nữa, điều này sẽ truyền đạt vấn đề đến toàn đội nhanh hơn sơ đồ hoặc tài liệu khác.
  2. Các bài kiểm tra đơn vị có thể đóng vai trò là ví dụ và tài liệu (một loại tài liệu thực sự biên dịch ) cùng với mã của bạn. Không giống như các tài liệu khác, bạn sẽ biết ngay lập tức khi hết hạn.
  3. Các thử nghiệm đơn vị có thể đóng vai trò là các chỉ số hiệu suất cơ bản khi cố gắng phân tách các vấn đề hiệu suất lớn hơn, trong khi các thử nghiệm tích hợp có xu hướng yêu cầu nhiều thiết bị để tìm ra vấn đề.

Có thể phân chia công việc của bạn (và thực thi phương pháp DRY) trong khi sử dụng cả hai bài kiểm tra Đơn vị và Tích hợp. Chỉ cần dựa vào các bài kiểm tra đơn vị cho các đơn vị chức năng nhỏ và không lặp lại bất kỳ logic nào đã có trong bài kiểm tra đơn vị trong bài kiểm tra tích hợp. Điều này thường sẽ dẫn đến công việc ít hơn (và do đó ít làm việc lại).


4

Các xét nghiệm rất hữu ích khi chúng phá vỡ: Chủ động hoặc Chủ động lại.

Kiểm tra đơn vị là chủ động và có thể là một xác minh chức năng liên tục trong khi Kiểm tra tích hợp có phản ứng trên dữ liệu theo giai đoạn / giả mạo.

Nếu hệ thống đang được xem xét gần / phụ thuộc vào dữ liệu hơn logic tính toán, Kiểm tra Tích hợp sẽ có tầm quan trọng cao hơn.

Ví dụ: nếu chúng tôi đang xây dựng một hệ thống ETL, các thử nghiệm phù hợp nhất sẽ xoay quanh dữ liệu (được dàn dựng, làm giả hoặc trực tiếp). Cùng một hệ thống sẽ có một số Bài kiểm tra đơn vị, nhưng chỉ xoay quanh việc xác nhận, lọc, v.v.

Mẫu lưu trữ không nên có logic tính toán hoặc kinh doanh. Nó rất gần với cơ sở dữ liệu. Nhưng kho lưu trữ cũng gần với logic kinh doanh sử dụng nó. Vì vậy, nó là một câu hỏi về nổi bật CÂN B .NG.

Kiểm tra đơn vị có thể kiểm tra CÁCH lưu trữ ứng xử. Kiểm tra tích hợp có thể kiểm tra những gì thực sự đã xảy ra khi kho lưu trữ được gọi.

Bây giờ, "CÁI GÌ THẬT SỰ ĐÃ XẢY RA" có vẻ rất hấp dẫn. Nhưng điều này có thể rất tốn kém cho việc chạy liên tục và lặp đi lặp lại. Định nghĩa cổ điển của các bài kiểm tra giòn áp dụng ở đây.

Vì vậy, hầu hết thời gian, tôi chỉ thấy nó đủ tốt để viết bài kiểm tra Đơn vị trên một đối tượng sử dụng kho lưu trữ. Bằng cách này, chúng tôi kiểm tra xem phương thức kho lưu trữ thích hợp có được gọi hay không và kết quả Mocked thích hợp được trả về.


Tôi thích điều này: "Bây giờ," CÁI GÌ THẬT SỰ ĐÃ XẢY RA "có vẻ rất hấp dẫn. Nhưng điều này có thể rất tốn kém khi chạy liên tục và lặp đi lặp lại."
atconway

2

Có 3 điều riêng biệt cần kiểm tra: thủ tục được lưu trữ, mã gọi thủ tục được lưu trữ (tức là lớp kho lưu trữ của bạn) và người tiêu dùng. Công việc của kho lưu trữ là tạo một truy vấn và chuyển đổi tập dữ liệu được trả về thành một đối tượng miền. Có đủ mã để hỗ trợ kiểm tra đơn vị tách biệt với thực thi truy vấn thực tế và tạo tập dữ liệu.

Vì vậy (đây là một ví dụ rất đơn giản):

interface IOrderRepository
{
    Order GetOrderByID(Guid id);
}

class OrderRepository : IOrderRepository
{
    private readonly ISqlExecutor sqlExecutor;
    public OrderRepository(ISqlExecutor sqlExecutor)
    {
        this.sqlExecutor = sqlExecutor;
    }

    public Order GetOrderByID(Guid id)
    {
        var sql = "SELECT blah, blah FROM Order WHERE OrderId = @p0";
        var dataset = this.sqlExecutor.Execute(sql, p0 = id);
        var result = this.orderFromDataset(dataset);
        return result;
    }
}

Sau đó, khi kiểm tra OrderRepository, chuyển vào một bản giả ISqlExecutorvà kiểm tra xem đối tượng được kiểm tra có chuyển đúng SQL không (công việc của nó) và trả về một Orderđối tượng thích hợp được cung cấp một số tập dữ liệu kết quả (cũng bị chế giễu). Có lẽ cách duy nhất để kiểm tra SqlExecutorlớp cụ thể là với các bài kiểm tra tích hợp, đủ công bằng, nhưng đó là lớp bao bọc mỏng và sẽ hiếm khi thay đổi, vì vậy rất lớn.

Bạn vẫn phải kiểm tra đơn vị thủ tục lưu trữ của bạn quá.


0

Tôi có thể giảm điều này xuống một dòng suy nghĩ rất đơn giản: Ưu tiên kiểm tra đơn vị vì nó giúp xác định vị trí lỗi. Và làm điều này một cách nhất quán vì sự không nhất quán gây ra nhầm lẫn.

Những lý do khác xuất phát từ cùng các quy tắc hướng dẫn phát triển OO vì chúng cũng áp dụng cho các thử nghiệm. Ví dụ, nguyên tắc trách nhiệm duy nhất.

Nếu một số bài kiểm tra đơn vị có vẻ như chúng không đáng làm, thì có lẽ đó là một dấu hiệu cho thấy chủ đề không thực sự có giá trị. Hoặc có lẽ chức năng của nó trừu tượng hơn so với đối tác của nó và các thử nghiệm cho nó (cũng như mã của nó) có thể được trừu tượng hóa lên mức cao hơn.

Như với bất cứ điều gì, có ngoại lệ. Và lập trình vẫn là một phần của một hình thức nghệ thuật nên nhiều vấn đề đủ khác nhau để đảm bảo đánh giá từng cách tiếp cận tốt nhất.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.