Làm thế nào để bạn biết những gì để kiểm tra khi viết bài kiểm tra đơn vị? [đóng cửa]


127

Sử dụng C #, tôi cần một lớp được gọi Usercó tên người dùng, mật khẩu, cờ hoạt động, tên, họ, tên đầy đủ, v.v.

Cần có phương pháp để xác thựccứu người dùng. Tôi chỉ cần viết một bài kiểm tra cho các phương pháp? Và tôi thậm chí có cần phải lo lắng về việc kiểm tra các thuộc tính vì chúng là getter và setters của .Net không?


Bài đăng này sẽ giúp thu hẹp câu hỏi rộng hơn: Earnestengineer.blogspot.com/2018/03/NH Bạn có thể thực hiện các hướng dẫn này để tập trung câu hỏi của mình
Lindsay Morsillo

Hãy nhớ rằng mật khẩu không nên được lưu trữ dưới dạng văn bản gốc.
Ông Anderson

Câu trả lời:


131

Nhiều câu trả lời tuyệt vời cho câu hỏi này cũng nằm trong câu hỏi của tôi: " Bắt đầu TDD - Thách thức? Giải pháp? Khuyến nghị? "

Tôi có thể khuyên bạn nên xem bài đăng trên blog của tôi (một phần lấy cảm hứng từ câu hỏi của tôi), tôi đã nhận được một số phản hồi tốt về điều đó. Cụ thể là:

Tôi không biết bắt đầu từ đâu?

  • Làm trở lại việc gì. Chỉ nghĩ về việc viết bài kiểm tra khi bạn đang viết mã mới. Đây có thể là hoạt động lại của mã cũ, hoặc một tính năng hoàn toàn mới.
  • Bắt đầu đơn giản. Đừng chạy đi và cố gắng làm cho đầu của bạn trở thành một khung kiểm tra cũng như là TDD-esque. Gỡ lỗi.Assert hoạt động tốt. Sử dụng nó như một điểm khởi đầu. Nó không gây rối với dự án của bạn hoặc tạo ra sự phụ thuộc.
  • Bắt đầu tích cực. Bạn đang cố gắng cải thiện nghề của bạn, cảm thấy tốt về nó. Tôi đã thấy rất nhiều nhà phát triển ngoài đó rất vui khi trì trệ và không thử những điều mới để cải thiện bản thân. Bạn đang làm điều đúng đắn, hãy nhớ điều này và nó sẽ giúp ngăn bạn từ bỏ.
  • Bắt đầu sẵn sàng cho một thử thách. Nó là khá khó để bắt đầu vào thử nghiệm. Mong đợi một thử thách, nhưng hãy nhớ - những thách thức có thể vượt qua.

Chỉ kiểm tra những gì bạn mong đợi

Tôi đã gặp vấn đề thực sự khi mới bắt đầu vì tôi liên tục ngồi đó cố gắng tìm ra mọi vấn đề có thể xảy ra và sau đó cố gắng kiểm tra và khắc phục. Đây là một cách nhanh chóng để đau đầu. Kiểm tra phải là một quá trình YAGNI thực sự. Nếu bạn biết có một vấn đề, sau đó viết một bài kiểm tra cho nó. Nếu không, đừng bận tâm.

Chỉ kiểm tra một điều

Mỗi trường hợp kiểm tra chỉ nên kiểm tra một điều. Nếu bạn từng thấy mình đặt tên và tên trong trường hợp thử nghiệm, bạn đã làm sai điều gì đó.

Tôi hy vọng điều này có nghĩa là chúng ta có thể chuyển từ "getters and setters" :)


2
"Nếu bạn biết có vấn đề, thì hãy viết một bài kiểm tra cho nó. Nếu không, đừng bận tâm." Tôi sẽ không đồng ý với cách nói này. Tôi có ấn tượng rằng các bài kiểm tra đơn vị sẽ bao gồm tất cả các đường dẫn thực thi có thể.
Corin Blaikie

3
Trong khi một số người có thể ủng hộ những điều như vậy, cá nhân tôi thì không. 90% đau đầu của tôi đến từ chỉ đơn giản là cố gắng làm "mọi thứ". Tôi nói kiểm tra cho những gì bạn mong đợi sẽ xảy ra (để bạn biết bạn đang nhận lại đúng giá trị) nhưng đừng thử và tìm ra tất cả. YAGNI.
Rob Cooper

4
Tôi cũng vậy, ủng hộ cách tiếp cận "kiểm tra lỗi của bạn". Nếu tất cả chúng ta đều có thời gian và sự kiên nhẫn vô hạn, chúng ta sẽ kiểm tra mọi con đường thực thi có thể. Nhưng chúng tôi không, vì vậy bạn phải dành nỗ lực của mình để nó có hiệu quả lớn nhất.
Schwern

63

Kiểm tra mã của bạn, không phải ngôn ngữ.

Một bài kiểm tra đơn vị như:

Integer i = new Integer(7);
assert (i.instanceOf(integer));

chỉ hữu ích nếu bạn đang viết một trình biên dịch và có khả năng khác instanceofkhông là phương thức của bạn không hoạt động.

Đừng kiểm tra những thứ mà bạn có thể dựa vào ngôn ngữ để thực thi. Trong trường hợp của bạn, tôi tập trung vào các phương thức xác thực và lưu của bạn - và tôi sẽ viết các bài kiểm tra để đảm bảo rằng chúng có thể xử lý các giá trị null trong bất kỳ hoặc tất cả các trường đó một cách duyên dáng.


1
Điểm hay về "Đừng kiểm tra khung" - Một cái gì đó tôi đã gặp phải khi mới làm điều này. + 1'ed :)
Rob Cooper

38

Điều này đã đưa tôi vào thử nghiệm đơn vị và nó làm tôi rất hạnh phúc

Chúng tôi chỉ mới bắt đầu làm thử nghiệm đơn vị. Trong một thời gian dài, tôi biết sẽ tốt khi bắt đầu thực hiện nhưng tôi không biết bắt đầu như thế nào và quan trọng hơn là phải kiểm tra cái gì.

Sau đó, chúng tôi đã phải viết lại một đoạn mã quan trọng trong chương trình kế toán của chúng tôi. Phần này rất phức tạp vì nó liên quan đến rất nhiều tình huống khác nhau. Phần tôi đang nói đến là một phương thức thanh toán hóa đơn bán hàng và / hoặc mua hàng đã được nhập vào hệ thống kế toán.

Tôi chỉ không biết làm thế nào để bắt đầu mã hóa nó, vì có rất nhiều lựa chọn thanh toán khác nhau. Hóa đơn có thể là 100 đô la nhưng khách hàng chỉ chuyển 99 đô la. Có thể bạn đã gửi hóa đơn bán hàng cho một khách hàng nhưng bạn cũng đã mua từ khách hàng đó. Vì vậy, bạn đã bán anh ta với giá 300 đô la nhưng bạn đã mua với giá 100 đô la. Bạn có thể mong đợi khách hàng của bạn trả cho bạn 200 đô la để giải quyết số dư. Và nếu bạn bán được 500 đô la nhưng khách hàng chỉ trả cho bạn 250 đô la thì sao?

Vì vậy, tôi đã có một vấn đề rất phức tạp để giải quyết với nhiều khả năng rằng một kịch bản sẽ hoạt động hoàn hảo nhưng sẽ sai đối với một loại kết hợp thanh toán / thanh toán khác.

Đây là nơi thử nghiệm đơn vị đã đến để giải cứu.

Tôi bắt đầu viết (bên trong mã kiểm tra) một phương pháp để tạo danh sách hóa đơn, cả cho bán hàng và mua hàng. Sau đó, tôi đã viết một phương thức thứ hai để tạo ra khoản thanh toán thực tế. Thông thường người dùng sẽ nhập thông tin đó thông qua giao diện người dùng.

Sau đó, tôi đã tạo TestMethod đầu tiên, thử nghiệm thanh toán rất đơn giản cho một hóa đơn mà không có bất kỳ khoản chiết khấu thanh toán nào. Tất cả các hành động trong hệ thống sẽ xảy ra khi một khoản thanh toán ngân hàng sẽ được lưu vào cơ sở dữ liệu. Như bạn có thể thấy tôi đã tạo hóa đơn, tạo thanh toán (giao dịch ngân hàng) và lưu giao dịch vào đĩa. Trong các xác nhận của mình, tôi đặt số nào phải là số chính xác kết thúc trong giao dịch Ngân hàng và Hóa đơn được liên kết. Tôi kiểm tra số lượng thanh toán, số tiền thanh toán, số tiền chiết khấu và số dư của hóa đơn sau khi giao dịch.

Sau khi chạy thử, tôi sẽ vào cơ sở dữ liệu và kiểm tra lại xem những gì tôi mong đợi có ở đó không.

Sau khi tôi viết bài kiểm tra, tôi bắt đầu mã hóa phương thức thanh toán (một phần của lớp BankHeader). Trong mã hóa tôi chỉ bận tâm với mã để thực hiện bài kiểm tra đầu tiên. Tôi chưa nghĩ về các kịch bản khác, phức tạp hơn.

Tôi đã chạy thử nghiệm đầu tiên, sửa một lỗi nhỏ cho đến khi thử nghiệm của tôi vượt qua.

Sau đó, tôi bắt đầu viết bài kiểm tra thứ hai, lần này làm việc với chiết khấu thanh toán. Sau khi tôi viết bài kiểm tra, tôi đã sửa đổi phương thức thanh toán để hỗ trợ giảm giá.

Trong khi kiểm tra tính chính xác với chiết khấu thanh toán, tôi cũng đã thử nghiệm thanh toán đơn giản. Tất cả các bài kiểm tra nên vượt qua tất nhiên.

Sau đó, tôi làm việc theo cách của tôi xuống các kịch bản phức tạp hơn.

1) Nghĩ về một kịch bản mới

2) Viết một bài kiểm tra cho kịch bản đó

3) Chạy thử nghiệm đơn đó để xem nó có vượt qua không

4) Nếu nó không gỡ lỗi và sửa đổi mã cho đến khi nó vượt qua.

5) Trong khi sửa đổi mã, tôi tiếp tục chạy tất cả các bài kiểm tra

Đây là cách tôi quản lý để tạo phương thức thanh toán rất phức tạp của mình. Không có kiểm thử đơn vị, tôi không biết làm thế nào để bắt đầu viết mã, vấn đề dường như quá lớn. Với thử nghiệm, tôi có thể bắt đầu với một phương pháp đơn giản và từng bước mở rộng nó với sự đảm bảo rằng các kịch bản đơn giản hơn vẫn sẽ hoạt động.

Tôi chắc chắn rằng việc sử dụng thử nghiệm đơn vị đã giúp tôi tiết kiệm được một vài ngày (hoặc vài tuần) mã hóa và ít nhiều đảm bảo tính chính xác của phương pháp của tôi.

Nếu sau này tôi nghĩ ra một kịch bản mới, tôi có thể thêm nó vào các thử nghiệm để xem nó có hoạt động hay không. Nếu không tôi có thể sửa đổi mã nhưng vẫn chắc chắn các kịch bản khác vẫn hoạt động chính xác. Điều này sẽ tiết kiệm ngày và ngày trong giai đoạn bảo trì và sửa lỗi.

Có, ngay cả mã được kiểm tra vẫn có thể có lỗi nếu người dùng thực hiện những việc bạn không nghĩ hoặc ngăn cản anh ta thực hiện

Dưới đây chỉ là một số thử nghiệm tôi đã tạo để kiểm tra phương thức thanh toán của mình.

public class TestPayments
{
    InvoiceDiaryHeader invoiceHeader = null;
    InvoiceDiaryDetail invoiceDetail = null;
    BankCashDiaryHeader bankHeader = null;
    BankCashDiaryDetail bankDetail = null;



    public InvoiceDiaryHeader CreateSales(string amountIncVat, bool sales, int invoiceNumber, string date)
    {
        ......
        ......
    }

    public BankCashDiaryHeader CreateMultiplePayments(IList<InvoiceDiaryHeader> invoices, int headerNumber, decimal amount, decimal discount)
    {
       ......
       ......
       ......
    }


    [TestMethod]
    public void TestSingleSalesPaymentNoDiscount()
    {
        IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>();
        list.Add(CreateSales("119", true, 1, "01-09-2008"));
        bankHeader = CreateMultiplePayments(list, 1, 119.00M, 0);
        bankHeader.Save();

        Assert.AreEqual(1, bankHeader.BankCashDetails.Count);
        Assert.AreEqual(1, bankHeader.BankCashDetails[0].Payments.Count);
        Assert.AreEqual(119M, bankHeader.BankCashDetails[0].Payments[0].PaymentAmount);
        Assert.AreEqual(0M, bankHeader.BankCashDetails[0].Payments[0].PaymentDiscount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[0].InvoiceHeader.Balance);
    }

    [TestMethod]
    public void TestSingleSalesPaymentDiscount()
    {
        IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>();
        list.Add(CreateSales("119", true, 2, "01-09-2008"));
        bankHeader = CreateMultiplePayments(list, 2, 118.00M, 1M);
        bankHeader.Save();

        Assert.AreEqual(1, bankHeader.BankCashDetails.Count);
        Assert.AreEqual(1, bankHeader.BankCashDetails[0].Payments.Count);
        Assert.AreEqual(118M, bankHeader.BankCashDetails[0].Payments[0].PaymentAmount);
        Assert.AreEqual(1M, bankHeader.BankCashDetails[0].Payments[0].PaymentDiscount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[0].InvoiceHeader.Balance);
    }

    [TestMethod]
    [ExpectedException(typeof(ApplicationException))]
    public void TestDuplicateInvoiceNumber()
    {
        IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>();
        list.Add(CreateSales("100", true, 2, "01-09-2008"));
        list.Add(CreateSales("200", true, 2, "01-09-2008"));

        bankHeader = CreateMultiplePayments(list, 3, 300, 0);
        bankHeader.Save();
        Assert.Fail("expected an ApplicationException");
    }

    [TestMethod]
    public void TestMultipleSalesPaymentWithPaymentDiscount()
    {
        IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>();
        list.Add(CreateSales("119", true, 11, "01-09-2008"));
        list.Add(CreateSales("400", true, 12, "02-09-2008"));
        list.Add(CreateSales("600", true, 13, "03-09-2008"));
        list.Add(CreateSales("25,40", true, 14, "04-09-2008"));

        bankHeader = CreateMultiplePayments(list, 5, 1144.00M, 0.40M);
        bankHeader.Save();

        Assert.AreEqual(1, bankHeader.BankCashDetails.Count);
        Assert.AreEqual(4, bankHeader.BankCashDetails[0].Payments.Count);
        Assert.AreEqual(118.60M, bankHeader.BankCashDetails[0].Payments[0].PaymentAmount);
        Assert.AreEqual(400, bankHeader.BankCashDetails[0].Payments[1].PaymentAmount);
        Assert.AreEqual(600, bankHeader.BankCashDetails[0].Payments[2].PaymentAmount);
        Assert.AreEqual(25.40M, bankHeader.BankCashDetails[0].Payments[3].PaymentAmount);

        Assert.AreEqual(0.40M, bankHeader.BankCashDetails[0].Payments[0].PaymentDiscount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[1].PaymentDiscount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[2].PaymentDiscount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[3].PaymentDiscount);

        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[0].InvoiceHeader.Balance);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[1].InvoiceHeader.Balance);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[2].InvoiceHeader.Balance);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[3].InvoiceHeader.Balance);
    }

    [TestMethod]
    public void TestSettlement()
    {
        IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>();
        list.Add(CreateSales("300", true, 43, "01-09-2008")); //Sales
        list.Add(CreateSales("100", false, 6453, "02-09-2008")); //Purchase

        bankHeader = CreateMultiplePayments(list, 22, 200, 0);
        bankHeader.Save();

        Assert.AreEqual(1, bankHeader.BankCashDetails.Count);
        Assert.AreEqual(2, bankHeader.BankCashDetails[0].Payments.Count);
        Assert.AreEqual(300, bankHeader.BankCashDetails[0].Payments[0].PaymentAmount);
        Assert.AreEqual(-100, bankHeader.BankCashDetails[0].Payments[1].PaymentAmount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[0].InvoiceHeader.Balance);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[1].InvoiceHeader.Balance);
    }

1
Tìm thấy một lỗi trong bài kiểm tra đơn vị của bạn! Bạn lặp lại dòng này thay vì bao gồm 2 trong một trong số chúng:Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[3].InvoiceHeader.Balance);
Ryan Peschel

2
Bạn nói: "Sau khi chạy thử, tôi sẽ vào cơ sở dữ liệu và kiểm tra lại xem những gì tôi mong đợi có ở đó không." Đây là một ví dụ tốt về kiểm tra tích hợp giữa các thành phần trong hệ thống của bạn - không phải là kiểm tra đơn vị riêng biệt của một đoạn mã.
JTech

2
Bạn cũng đã phá vỡ quy tắc nhiều hơn một Xác nhận cho mỗi bài kiểm tra.
Steve

13

Nếu chúng thực sự là tầm thường, thì đừng bận tâm thử nghiệm. Ví dụ, nếu chúng được thực hiện như thế này;

public class User
{
    public string Username { get; set; }
    public string Password { get; set; }
}

Mặt khác, nếu bạn đang làm một cái gì đó thông minh, (như mã hóa và giải mã mật khẩu trong getter / setter) thì hãy kiểm tra nó.


10

Quy tắc là bạn phải kiểm tra từng đoạn logic bạn viết. Nếu bạn thực hiện một số chức năng cụ thể trong getters và setters tôi nghĩ rằng chúng đáng để thử nghiệm. Nếu họ chỉ gán giá trị cho một số trường riêng tư, đừng bận tâm.


6

Câu hỏi này dường như là một câu hỏi về nơi mà người ta vẽ đường thẳng về phương pháp nào được thử nghiệm và phương pháp nào không.

Các setters và getters để gán giá trị đã được tạo ra với sự nhất quán và tăng trưởng trong tương lai, và thấy trước rằng một lúc nào đó, setter / getter có thể phát triển thành các hoạt động phức tạp hơn. Sẽ có ý nghĩa khi đặt các thử nghiệm đơn vị của các phương pháp đó, cũng vì mục đích nhất quán và tăng trưởng trong tương lai.

Độ tin cậy của mã, đặc biệt là trong khi trải qua thay đổi để thêm chức năng bổ sung, là mục tiêu chính. Tôi không biết bất kỳ ai từng bị sa thải vì bao gồm cả setters / getters trong phương pháp thử nghiệm, nhưng tôi chắc chắn rằng có những người muốn họ đã thử nghiệm các phương pháp mà họ biết hoặc có thể nhớ lại là các trình bao / lấy đơn giản nhưng không phải vậy trường hợp dài hơn.

Có thể một thành viên khác trong nhóm đã mở rộng các phương thức set / get để bao gồm logic hiện cần thử nghiệm nhưng sau đó không tạo ra các thử nghiệm. Nhưng hiện tại, mã của bạn đang gọi các phương thức này và bạn không biết chúng đã thay đổi và cần thử nghiệm chuyên sâu, và thử nghiệm bạn thực hiện trong quá trình phát triển và QA không kích hoạt lỗi, nhưng dữ liệu kinh doanh thực sự vào ngày đầu tiên phát hành kích hoạt nó.

Bây giờ hai đồng đội sẽ tranh luận về việc ai đã làm rơi trái bóng và thất bại trong các bài kiểm tra đơn vị khi tập hợp / bị biến đổi để bao gồm logic có thể thất bại nhưng không được bao phủ bởi bài kiểm tra đơn vị. Đồng đội ban đầu đã viết tập hợp / nhận sẽ có một thời gian dễ dàng hơn để làm sạch này nếu các bài kiểm tra được thực hiện từ ngày đầu tiên trên tập / đơn giản.

Ý kiến ​​của tôi là một vài phút "lãng phí" thời gian bao gồm TẤT CẢ các phương pháp với các bài kiểm tra đơn vị, thậm chí là tầm thường, có thể giúp tiết kiệm nhiều ngày đau đầu và mất tiền / danh tiếng của doanh nghiệp và mất việc của ai đó.

Và thực tế là bạn đã thực hiện các phương pháp tầm thường với các bài kiểm tra đơn vị có thể được nhìn thấy bởi người đồng đội cơ sở đó khi họ thay đổi các phương pháp tầm thường thành các phương pháp không tầm thường và nhắc họ cập nhật bài kiểm tra, và bây giờ không có ai gặp rắc rối vì lỗi này được chứa từ đạt đến sản xuất.

Cách chúng tôi viết mã và kỷ luật có thể nhìn thấy từ mã của chúng tôi có thể giúp người khác.


4

Một câu trả lời kinh điển khác. Điều này, tôi tin, từ Ron Jeffries:

Chỉ kiểm tra mã mà bạn muốn làm việc.


3

Kiểm tra mã soạn sẵn là một sự lãng phí thời gian, nhưng như Slavo nói, nếu bạn thêm một hiệu ứng phụ vào getters / setters của mình, thì bạn nên viết một bài kiểm tra để đi kèm với chức năng đó.

Nếu bạn đang thực hiện phát triển dựa trên thử nghiệm, trước tiên bạn nên viết hợp đồng (ví dụ: giao diện), sau đó viết (các) thử nghiệm để thực hiện giao diện đó ghi lại kết quả / hành vi dự kiến. Sau đó tự viết phương thức của bạn mà không cần chạm vào mã trong các bài kiểm tra đơn vị của bạn. Cuối cùng, lấy một công cụ bao phủ mã và đảm bảo các bài kiểm tra của bạn thực hiện tất cả các đường dẫn logic trong mã của bạn.


3

Mã thực sự tầm thường như getters và setters không có hành vi bổ sung hơn là thiết lập một trường riêng là quá mức cần thiết để kiểm tra. Trong 3.0 C # thậm chí có một số đường cú pháp trong đó trình biên dịch sẽ chăm sóc trường riêng để bạn không phải lập trình điều đó.

Tôi thường viết rất nhiều bài kiểm tra rất đơn giản để xác minh hành vi mà tôi mong đợi từ các lớp học của mình. Ngay cả khi đó là những thứ đơn giản như thêm hai số. Tôi chuyển đổi rất nhiều giữa việc viết một bài kiểm tra đơn giản và viết một số dòng mã. Lý do cho điều này là sau đó tôi có thể thay đổi mã mà không sợ tôi phá vỡ những điều tôi không nghĩ tới.


Rất vui vì bạn đã thực hiện tốt điểm của nguyên tắc KISS .. Tôi thường có các bài kiểm tra có nghĩa đen giống như 2-3 dòng mã, các bài kiểm tra nhỏ, đơn giản. Dễ dàng mò mẫm và khó phá vỡ :) + 1'ed
Rob Cooper

3

Bạn nên kiểm tra mọi thứ. Ngay bây giờ bạn có getters và setters, nhưng một ngày nào đó bạn có thể thay đổi chúng một chút, có thể để xác nhận hoặc một cái gì đó khác. Các bài kiểm tra bạn viết hôm nay sẽ được sử dụng vào ngày mai để đảm bảo mọi thứ vẫn hoạt động như bình thường. Khi bạn viết bài kiểm tra, bạn nên quên những cân nhắc như "ngay bây giờ nó không quan trọng". Trong bối cảnh nhanh hoặc theo hướng kiểm tra, bạn nên kiểm tra giả định tái cấu trúc trong tương lai. Ngoài ra, bạn đã thử đưa vào các giá trị thực sự kỳ lạ như chuỗi cực dài hoặc nội dung "xấu" khác chưa? Chà, bạn không nên ... đừng bao giờ nghĩ rằng mã của bạn có thể bị lạm dụng trong tương lai.

Nói chung tôi thấy rằng viết bài kiểm tra người dùng rộng rãi là ở một bên, mệt mỏi. Mặt khác, mặc dù nó luôn mang đến cho bạn cái nhìn sâu sắc vô giá về cách ứng dụng của bạn sẽ hoạt động và giúp bạn loại bỏ các giả định dễ dàng (và sai) (như: tên người dùng sẽ luôn có độ dài dưới 1000 ký tự).


3

Đối với các mô-đun đơn giản có thể kết thúc trong bộ công cụ hoặc trong loại dự án nguồn mở, bạn nên kiểm tra càng nhiều càng tốt, bao gồm các getters và setters tầm thường. Điều bạn muốn ghi nhớ là việc tạo một bài kiểm tra đơn vị khi bạn viết một mô-đun cụ thể khá đơn giản và dễ hiểu. Thêm getters và setters là mã tối thiểu và có thể được xử lý mà không cần suy nghĩ nhiều. Tuy nhiên, khi mã của bạn được đặt trong một hệ thống lớn hơn, nỗ lực bổ sung này có thể bảo vệ bạn trước những thay đổi trong hệ thống cơ bản, chẳng hạn như thay đổi loại trong lớp cơ sở. Kiểm tra mọi thứ là cách tốt nhất để có hồi quy hoàn tất.


2

Sẽ không hại khi viết bài kiểm tra đơn vị cho getters và setters của bạn. Ngay bây giờ, họ có thể đang thực hiện các bộ / trường dưới mui xe, nhưng trong tương lai bạn có thể có logic xác thực hoặc các phụ thuộc giữa các thuộc tính cần được kiểm tra. Viết nó bây giờ dễ dàng hơn trong khi bạn đang nghĩ về nó sau đó ghi nhớ trang bị thêm nếu thời điểm đó đến.


tốt, nếu getters / setters của bạn cần kiểm tra đơn vị, phải có một số logic liên quan đến chúng, vì vậy điều đó có nghĩa là logic phải được viết bên trong chúng, nếu chúng không có logic nào, không cần phải kiểm tra đơn vị.
Pop Catalin

2
Quan điểm của ông là logic có thể được thêm vào chúng sau này.
Truyền thuyết Chiều dài

2

nói chung, khi một phương thức chỉ được xác định cho các giá trị nhất định, hãy kiểm tra các giá trị trên và trên đường biên của những gì được chấp nhận. Nói cách khác, đảm bảo phương pháp của bạn thực hiện những gì nó phải làm, nhưng không có gì hơn . Điều này rất quan trọng, bởi vì khi bạn sắp thất bại, bạn muốn thất bại sớm.

Trong hệ thống phân cấp thừa kế, đảm bảo kiểm tra sự tuân thủ LSP .

Việc kiểm tra getters và setters mặc định dường như không hữu ích cho tôi, trừ khi bạn dự định thực hiện một số xác nhận sau này.


2

tốt nếu bạn nghĩ rằng nó có thể phá vỡ, viết một bài kiểm tra cho nó. Tôi thường không kiểm tra setter / getter, nhưng giả sử bạn tạo một cái cho User.Name, nối tên và họ, tôi sẽ viết một bài kiểm tra để nếu ai đó thay đổi thứ tự cho họ và tên, ít nhất anh ta sẽ biết ông đã thay đổi một cái gì đó đã được thử nghiệm.


2

Câu trả lời kinh điển là "kiểm tra bất cứ điều gì có thể phá vỡ." Nếu bạn chắc chắn các thuộc tính sẽ không bị hỏng, đừng kiểm tra chúng.

Và một khi một cái gì đó được tìm thấy đã bị hỏng (bạn tìm thấy một lỗi), rõ ràng nó có nghĩa là bạn cần phải kiểm tra nó. Viết một bài kiểm tra để tái tạo lỗi, xem nó thất bại, sau đó sửa lỗi, sau đó xem vượt qua bài kiểm tra.


1

Theo tôi hiểu các bài kiểm tra đơn vị trong bối cảnh phát triển nhanh, Mike, vâng, bạn cần kiểm tra các getters và setters (giả sử chúng được hiển thị công khai). Toàn bộ khái niệm kiểm thử đơn vị là kiểm tra đơn vị phần mềm, là một lớp trong trường hợp này, dưới dạng hộp đen . Vì các getters và setters có thể nhìn thấy bên ngoài, bạn cần kiểm tra chúng cùng với Xác thực và Lưu.


1

Nếu các phương thức Xác thực và Lưu sử dụng các thuộc tính, thì các thử nghiệm của bạn sẽ gián tiếp chạm vào các thuộc tính. Miễn là các thuộc tính chỉ cung cấp quyền truy cập vào dữ liệu, thì không cần thiết phải kiểm tra rõ ràng (trừ khi bạn sẽ bảo hiểm 100%).


1

Tôi sẽ kiểm tra getters và setters của bạn. Tùy thuộc vào người viết mã, một số người thay đổi ý nghĩa của các phương thức getter / setter. Tôi đã thấy khởi tạo biến và xác nhận khác là một phần của phương thức getter. Để kiểm tra loại điều này, bạn muốn kiểm tra đơn vị bao gồm mã đó một cách rõ ràng.


1

Cá nhân tôi sẽ "kiểm tra bất cứ thứ gì có thể phá vỡ" và getter đơn giản (hoặc thậm chí các thuộc tính tự động tốt hơn) sẽ không bị hỏng. Tôi chưa bao giờ có một tuyên bố trở lại đơn giản thất bại và do đó không bao giờ có thử nghiệm cho họ. Nếu các getters có tính toán trong chúng hoặc một số dạng câu lệnh khác, tôi chắc chắn sẽ thêm các bài kiểm tra cho chúng.

Cá nhân tôi sử dụng Moq như một khung đối tượng giả và sau đó xác minh rằng đối tượng của tôi gọi các đối tượng xung quanh theo cách nó nên.


1

Bạn phải bao gồm việc thực hiện mọi phương thức của lớp bằng UT và kiểm tra giá trị trả về của phương thức. Điều này bao gồm getters và setters, đặc biệt trong trường hợp các thành viên (thuộc tính) là các lớp phức tạp, đòi hỏi phân bổ bộ nhớ lớn trong quá trình khởi tạo của chúng. Gọi setter với một số chuỗi rất lớn chẳng hạn (hoặc một cái gì đó có ký hiệu Hy Lạp) và kiểm tra kết quả có đúng không (không bị cắt cụt, mã hóa tốt, v.v.)

Trong trường hợp số nguyên đơn giản cũng được áp dụng - điều gì xảy ra nếu bạn vượt qua lâu thay vì số nguyên? Đó là lý do bạn viết UT cho :)


1

Tôi sẽ không kiểm tra các thiết lập thực tế của tài sản. Tôi sẽ quan tâm nhiều hơn về cách những tài sản đó được người tiêu dùng yêu thích và những gì họ đưa vào. Với bất kỳ thử nghiệm nào, bạn phải cân nhắc rủi ro với thời gian / chi phí thử nghiệm.


1

Bạn nên kiểm tra "mọi khối mã không tầm thường" bằng cách sử dụng các bài kiểm tra đơn vị càng nhiều càng tốt.

Nếu các thuộc tính của bạn là tầm thường và không chắc ai đó sẽ đưa ra một lỗi trong đó, thì nó không an toàn để không kiểm tra đơn vị chúng.

Các phương thức Xác thực () và Lưu () của bạn trông giống như các ứng cử viên tốt để thử nghiệm.


1

Lý tưởng nhất là bạn đã thực hiện bài kiểm tra đơn vị của bạn khi bạn đang viết lớp. Đây là cách bạn muốn làm điều đó khi sử dụng Phát triển hướng thử nghiệm. Bạn thêm các bài kiểm tra khi bạn thực hiện từng điểm chức năng, đảm bảo rằng bạn cũng bao gồm các trường hợp cạnh với bài kiểm tra.

Viết các bài kiểm tra sau đó là đau đớn hơn nhiều, nhưng có thể làm được.

Đây là những gì tôi sẽ làm ở vị trí của bạn:

  1. Viết một bộ kiểm tra cơ bản kiểm tra chức năng cốt lõi.
  2. Nhận NCover và chạy nó trong bài kiểm tra của bạn. Phạm vi kiểm tra của bạn có thể sẽ được khoảng 50% tại thời điểm này.
  3. Tiếp tục thêm các bài kiểm tra bao gồm các trường hợp cạnh của bạn cho đến khi bạn nhận được bảo hiểm khoảng 80% -90%

Điều này sẽ cung cấp cho bạn một bộ các bài kiểm tra đơn vị hoạt động tốt sẽ hoạt động như một bộ đệm tốt chống lại hồi quy.

Vấn đề duy nhất với cách tiếp cận này là mã phải được thiết kế để có thể kiểm tra theo kiểu này. Nếu bạn thực hiện bất kỳ lỗi ghép nối nào từ sớm, bạn sẽ không thể có được phạm vi bảo hiểm cao một cách dễ dàng.

Đây là lý do tại sao nó thực sự quan trọng để viết các bài kiểm tra trước khi bạn viết mã. Nó buộc bạn phải viết mã được ghép lỏng lẻo.


1

Đừng kiểm tra mã rõ ràng đang hoạt động. Vì vậy, nếu setters và getters của bạn chỉ là "propertyvalue = value" và "return propertyvalue" thì sẽ không có ý nghĩa gì khi kiểm tra nó.


1

Ngay cả get / set cũng có thể có những hậu quả kỳ lạ, tùy thuộc vào cách chúng được thực hiện, vì vậy chúng nên được coi là phương thức.

Mỗi thử nghiệm trong số này sẽ cần chỉ định các bộ tham số cho các thuộc tính, xác định cả hai thuộc tính có thể chấp nhận và không được chấp nhận để đảm bảo trả lại / thất bại cuộc gọi theo cách mong đợi.

Bạn cũng cần lưu ý về vấn đề bảo mật, như một ví dụ SQL và kiểm tra những thứ này.

Vì vậy, có, bạn cần phải lo lắng về việc kiểm tra các thuộc tính.


1

Tôi tin rằng thật ngớ ngẩn khi kiểm tra getters & setters khi họ chỉ thực hiện một thao tác đơn giản. Cá nhân tôi không viết các bài kiểm tra đơn vị phức tạp để bao gồm bất kỳ mẫu sử dụng nào. Tôi cố gắng viết đủ các bài kiểm tra để đảm bảo tôi đã xử lý hành vi thực thi bình thường và nhiều trường hợp lỗi tôi có thể nghĩ ra. Tôi sẽ viết thêm các bài kiểm tra đơn vị như là một phản ứng với các báo cáo lỗi. Tôi sử dụng thử nghiệm đơn vị để đảm bảo mã đáp ứng các yêu cầu và để sửa đổi trong tương lai dễ dàng hơn. Tôi cảm thấy sẵn sàng hơn nhiều để thay đổi mã khi tôi biết rằng nếu tôi phá vỡ một cái gì đó, một bài kiểm tra sẽ thất bại.


1

Tôi sẽ viết một bài kiểm tra cho bất cứ điều gì bạn đang viết mã cho điều đó có thể kiểm tra được bên ngoài giao diện GUI.

Thông thường, bất kỳ logic nào tôi viết có bất kỳ logic nghiệp vụ nào tôi đặt bên trong lớp logic hoặc lớp nghiệp vụ khác.

Sau đó viết bài kiểm tra cho bất cứ điều gì làm một cái gì đó dễ dàng để làm.

Trước hết, hãy viết một bài kiểm tra đơn vị cho từng phương thức công khai trong "Lớp logic nghiệp vụ" của bạn.

Nếu tôi có một lớp học như thế này:

   public class AccountService
    {
        public void DebitAccount(int accountNumber, double amount)
        {

        }

        public void CreditAccount(int accountNumber, double amount)
        {

        }

        public void CloseAccount(int accountNumber)
        {

        }
    }

Điều đầu tiên tôi sẽ làm trước khi tôi viết bất kỳ mã nào biết rằng tôi có những hành động này để thực hiện sẽ là bắt đầu viết các bài kiểm tra đơn vị.

   [TestFixture]
    public class AccountServiceTests
    {
        [Test]
        public void DebitAccountTest()
        {

        }

        [Test]
        public void CreditAccountTest()
        {

        }

        [Test]
        public void CloseAccountTest()
        {

        }
    }

Viết bài kiểm tra của bạn để xác nhận mã bạn đã viết để làm một cái gì đó. Nếu bạn lặp đi lặp lại một bộ sưu tập các thứ và thay đổi một cái gì đó về mỗi thứ đó, hãy viết một bài kiểm tra thực hiện điều tương tự và Khẳng định điều đó thực sự đã xảy ra.

Có rất nhiều cách tiếp cận khác mà bạn có thể thực hiện, cụ thể là Behavoir Driven Development (BDD), có liên quan nhiều hơn và không phải là nơi tuyệt vời để bắt đầu với các kỹ năng kiểm tra đơn vị của bạn.

Vì vậy, đạo đức của câu chuyện là, kiểm tra bất cứ điều gì làm bất cứ điều gì bạn có thể lo lắng, giữ cho bài kiểm tra đơn vị kiểm tra những thứ cụ thể có kích thước nhỏ, rất nhiều bài kiểm tra là tốt.

Giữ logic kinh doanh của bạn bên ngoài lớp Giao diện người dùng để bạn có thể dễ dàng viết bài kiểm tra cho họ và bạn sẽ ổn.

Tôi khuyên dùng TestDriven.Net hoặc ReSharper vì cả hai đều dễ dàng tích hợp vào Visual Studio.


1

Tôi sẽ khuyên bạn nên viết nhiều bài kiểm tra cho các phương thức Xác thực và Lưu của bạn. Ngoài trường hợp thành công (nơi cung cấp tất cả các tham số, mọi thứ đều được viết đúng chính tả, v.v.), tốt nhất là nên kiểm tra các trường hợp lỗi khác nhau (tham số không chính xác hoặc thiếu, kết nối cơ sở dữ liệu không khả dụng nếu có, v.v.). Tôi khuyên bạn nên thử nghiệm đơn vị thực dụng trong C # với NUnit làm tài liệu tham khảo.

Như những người khác đã nêu, các bài kiểm tra đơn vị cho getters và setters là quá mức cần thiết, trừ khi có logic có điều kiện trong getters và setters của bạn.


1

Mặc dù có thể đoán chính xác nơi mã của bạn cần kiểm tra, nhưng tôi thường nghĩ rằng bạn cần số liệu để sao lưu dự đoán này. Kiểm tra đơn vị theo quan điểm của tôi đi đôi với các số liệu bảo hiểm mã.

Mã với rất nhiều bài kiểm tra nhưng phạm vi bảo hiểm nhỏ chưa được kiểm tra tốt. Điều đó nói rằng, mã với phạm vi bảo hiểm 100% nhưng không kiểm tra các trường hợp ràng buộc và lỗi cũng không lớn.

Bạn muốn cân bằng giữa độ bao phủ cao (tối thiểu 90%) và dữ liệu đầu vào biến đổi.

Hãy nhớ kiểm tra "rác trong"!

Ngoài ra, kiểm tra đơn vị không phải là kiểm tra đơn vị trừ khi kiểm tra lỗi. Các bài kiểm tra đơn vị không có xác nhận hoặc được đánh dấu bằng các ngoại lệ đã biết sẽ chỉ kiểm tra xem mã không chết khi chạy!

Bạn cần thiết kế các bài kiểm tra của mình để chúng luôn báo cáo các lỗi hoặc dữ liệu không mong muốn / không mong muốn!


1

Nó làm cho mã của chúng tôi tốt hơn ... thời gian!

Một điều mà chúng tôi các nhà phát triển phần mềm quên mất khi thực hiện phát triển theo hướng kiểm tra là mục đích đằng sau các hành động của chúng tôi. Nếu một bài kiểm tra đơn vị đang được viết sau khi đã có mã sản xuất, giá trị của bài kiểm tra sẽ giảm xuống (nhưng không bị mất hoàn toàn).

Theo tinh thần thực sự cho thử nghiệm đơn vị, các thử nghiệm này không chủ yếu ở đó để "kiểm tra" thêm mã của chúng tôi; hoặc để có được phạm vi bảo hiểm mã tốt hơn 90% -100%. Đây là tất cả các lợi ích bên lề của việc viết các bài kiểm tra đầu tiên. Phần thưởng lớn là mã kết thúc sản xuất của chúng tôi được viết tốt hơn nhiều do quy trình tự nhiên của TDD.

Để giúp truyền đạt tốt hơn ý tưởng này, những điều sau đây có thể hữu ích trong việc đọc:

Lý thuyết thiếu sót của các bài kiểm tra đơn vị
Phát triển phần mềm có mục đích

Nếu chúng tôi cảm thấy rằng hành động viết thêm các bài kiểm tra đơn vị là điều giúp chúng tôi có được một sản phẩm chất lượng cao hơn, thì chúng tôi có thể phải chịu đựng sự phát triển dựa trên thử nghiệm vận chuyển hàng hóa .


Tôi không đồng ý với khẳng định rằng các thử nghiệm đơn vị không có giá trị sau khi đã có mã sản xuất. Các xác nhận như vậy không giải thích cho tiện ích của chúng trong việc sao chép các điều kiện lỗi được tìm thấy trong sản xuất hoặc theo cách hiểu về mã được kế thừa từ nhà phát triển hoặc nhóm trước đó.
Scott Lawrence

Tôi có thể đã đi qua không chính xác. Tôi không có nghĩa là các bài kiểm tra đơn vị không có giá trị sau khi mã sản xuất được đưa ra. Tuy nhiên, giá trị của họ đi xuống. Lợi ích lớn nhất đối với thử nghiệm đơn vị đến từ phép thuật vốn có xảy ra khi chúng ta để chúng thúc đẩy sự phát triển sản xuất của chúng ta.
Scott Saad
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.