Làm thế nào bạn nên TDD một trò chơi Yahtzee?


36

Giả sử bạn đang viết một trò chơi TDD theo phong cách Yahtzee. Bạn muốn kiểm tra một phần của mã xác định xem một bộ năm cuộn chết có phải là một ngôi nhà đầy đủ hay không. Theo tôi biết, khi làm TDD, bạn tuân thủ các nguyên tắc sau:

  • Viết bài kiểm tra trước
  • Viết điều đơn giản nhất có thể có hiệu quả
  • Tinh chỉnh và tái cấu trúc

Vì vậy, một thử nghiệm ban đầu có thể trông giống như thế này:

public void Returns_true_when_roll_is_full_house()
{
    FullHouseTester sut = new FullHouseTester();
    var actual = sut.IsFullHouse(1, 1, 1, 2, 2);

    Assert.IsTrue(actual);
}

Khi làm theo "Viết điều đơn giản nhất có thể có hiệu quả", bây giờ bạn nên viết IsFullHousephương thức như thế này:

public bool IsFullHouse(int roll1, int roll2, int roll3, int roll4, int roll5)
{
    if (roll1 == 1 && roll2 == 1 && roll3 == 1 && roll4 == 2 && roll5 == 2)
    {
        return true;
    }

    return false;
}

Điều này dẫn đến một thử nghiệm xanh nhưng việc thực hiện không đầy đủ.

Bạn có nên kiểm tra đơn vị mọi sự kết hợp hợp lệ có thể (cả giá trị và vị trí) cho một ngôi nhà đầy đủ không? Điều đó có vẻ như là cách duy nhất để hoàn toàn chắc chắn rằng IsFullHousemã của bạn đã được kiểm tra và sửa chữa hoàn toàn, nhưng cũng có vẻ khá điên rồ khi làm điều đó.

Làm thế nào bạn sẽ đơn vị kiểm tra một cái gì đó như thế này?

Cập nhật

Erik và Kilian chỉ ra rằng sử dụng nghĩa đen trong triển khai ban đầu để có được bài kiểm tra xanh có thể không phải là ý tưởng tốt nhất. Tôi muốn giải thích lý do tại sao tôi làm điều đó và lời giải thích đó không phù hợp với một nhận xét.

Kinh nghiệm thực tế của tôi với thử nghiệm đơn vị (đặc biệt là sử dụng phương pháp TDD) rất hạn chế. Tôi nhớ đã xem bản ghi âm TDD Master Class của Roy Osherove trên Tekpub. Trong một trong những tập phim, anh xây dựng kiểu TDD String Calculator. Thông số đầy đủ của Máy tính chuỗi có thể được tìm thấy ở đây: http://osherove.com/tdd-kata-1/

Anh ta bắt đầu với một bài kiểm tra như thế này:

public void Add_with_empty_string_should_return_zero()
{
    StringCalculator sut = new StringCalculator();
    int result = sut.Add("");

    Assert.AreEqual(0, result);
}

Điều này dẫn đến việc thực hiện Addphương pháp đầu tiên này :

public int Add(string input)
{
    return 0;
}

Sau đó, bài kiểm tra này được thêm vào:

public void Add_with_one_number_string_should_return_number()
{
    StringCalculator sut = new StringCalculator();
    int result = sut.Add("1");

    Assert.AreEqual(1, result);
}

Addphương pháp được tái cấu trúc:

public int Add(string input)
{
    if (input.Length == 0)
    {
        return 0;
    }

    return 1;
}

Sau mỗi bước, Roy nói "Viết điều đơn giản nhất sẽ hoạt động".

Vì vậy, tôi nghĩ rằng tôi sẽ thử cách tiếp cận này khi thử làm một trò chơi Yahtzee theo phong cách TDD.


8
"Viết điều đơn giản nhất có thể có hiệu quả" thực sự là viết tắt; lời khuyên chính xác là "Viết điều đơn giản nhất có thể không hoàn toàn bản lĩnh và rõ ràng là không chính xác mà hoạt động". Vì vậy, không, bạn không nên viếtif (roll1 == 1 && roll2 == 1 && roll3 == 1 && roll4 == 2 && roll5 == 2)
Carson63000

3
Cảm ơn bạn đã tóm tắt câu trả lời của Erik, theo cách ít tranh luận hoặc văn minh hơn.
Kristof Claes

1
"Viết điều đơn giản nhất có hiệu quả", như @ Carson63000, thực sự là một sự đơn giản hóa. Thật nguy hiểm khi nghĩ như thế; nó dẫn đến sự kiện Sudoku TDD khét tiếng (google nó). Khi bị theo dõi một cách mù quáng, TDD thực sự rất dũng cảm: bạn không thể khái quát một thuật toán không tầm thường bằng cách mù quáng làm "điều đơn giản nhất có hiệu quả" ... bạn phải thực sự nghĩ! Thật không may, ngay cả những người được cho là bậc thầy của XP và TDD đôi khi cũng theo dõi nó một cách mù quáng ...
Andres F.

1
@AresresF. Lưu ý rằng nhận xét của bạn đã xuất hiện cao hơn trong các tìm kiếm của Google so với phần lớn các bình luận về "sự thất bại TDD của Soduko" sau chưa đầy ba ngày. Tuy nhiên Làm thế nào để không giải quyết Sudoku tóm tắt: TDD là cho chất lượng, không phải là chính xác. Bạn cần giải thuật toán trước khi bắt đầu viết mã, đặc biệt là với TDD. (Không phải tôi cũng không phải là lập trình viên mã đầu tiên.)
Mark Hurd

1
pvv.org/~oma/TDDinC_Yahtzee_27oct2011.pdf có thể được quan tâm.

Câu trả lời:


40

Đã có rất nhiều câu trả lời hay cho câu hỏi này, và tôi đã nhận xét và đánh giá cao một vài trong số chúng. Tuy nhiên, tôi muốn thêm một số suy nghĩ.

Linh hoạt không dành cho người mới

OP nói rõ rằng anh ta không có kinh nghiệm với TDD và tôi nghĩ rằng một câu trả lời tốt phải tính đến điều đó. Theo thuật ngữ của mô hình thu nhận kỹ năng của Dreyfus , anh ta có lẽ là một Novice . Không có gì sai khi là người mới - tất cả chúng ta đều là người mới khi chúng ta bắt đầu học một cái gì đó mới. Tuy nhiên, những gì mô hình Dreyfus giải thích là người mới được đặc trưng bởi

  • tuân thủ cứng nhắc các quy tắc hoặc kế hoạch được dạy
  • không thực hiện phán đoán tùy ý

Đó không phải là một mô tả về sự thiếu hụt tính cách, vì vậy không có lý do gì phải xấu hổ về điều đó - đó là giai đoạn tất cả chúng ta cần phải trải qua để học một cái gì đó mới.

Điều này cũng đúng với TDD.

Mặc dù tôi đồng ý với nhiều câu trả lời khác ở đây rằng TDD không cần phải giáo điều, và đôi khi có thể có ích hơn khi làm việc theo cách khác, điều đó không giúp được ai mới bắt đầu. Làm thế nào bạn có thể thực hiện phán đoán tùy ý khi bạn không có kinh nghiệm?

Nếu một người mới chấp nhận lời khuyên rằng đôi khi không nên làm TDD, làm thế nào anh ta hoặc cô ta có thể xác định khi nào nên bỏ qua TDD?

Không có kinh nghiệm hoặc hướng dẫn, điều duy nhất một người mới có thể làm là bỏ qua TDD mỗi khi nó trở nên quá khó khăn. Đó là bản chất của con người, nhưng không phải là một cách tốt để học hỏi.

Nghe các bài kiểm tra

Bỏ qua TDD bất cứ khi nào nó trở nên khó khăn là bỏ lỡ một trong những lợi ích quan trọng nhất của TDD. Các thử nghiệm cung cấp phản hồi sớm về API của SUT. Nếu bài kiểm tra khó viết, đó là một dấu hiệu quan trọng cho thấy SUT khó sử dụng.

Đây là lý do tại sao một trong những thông điệp quan trọng nhất của GOOS là: lắng nghe bài kiểm tra của bạn!

Trong trường hợp của câu hỏi này, phản ứng đầu tiên của tôi khi nhìn thấy API được đề xuất của trò chơi Yahtzee và cuộc thảo luận về tổ hợp có thể tìm thấy trên trang này, đó là đây là phản hồi quan trọng về API.

API có phải biểu diễn các cuộn súc sắc như một chuỗi số nguyên được sắp xếp không? Đối với tôi, mùi ám ảnh nguyên thủy đó . Đó là lý do tại sao tôi rất vui khi thấy câu trả lời từ Tallseth gợi ý về việc giới thiệu một Rolllớp học. Tôi nghĩ đó là một gợi ý tuyệt vời.

Tuy nhiên, tôi nghĩ rằng một số ý kiến ​​cho câu trả lời đó đã sai. Điều mà TDD sau đó gợi ý là một khi bạn có ý tưởng rằng một Rolllớp học sẽ là một ý tưởng tốt, bạn tạm ngưng công việc trên SUT ban đầu và bắt đầu làm việc với TDD'ing Rolllớp.

Mặc dù tôi đồng ý rằng TDD nhắm vào "con đường hạnh phúc" hơn là nhằm mục đích thử nghiệm toàn diện, nhưng nó vẫn giúp chia hệ thống thành các đơn vị có thể quản lý được. Một Rolllớp học có vẻ như một cái gì đó bạn có thể TDD hoàn thành dễ dàng hơn nhiều.

Sau đó, một khi Rolllớp học được phát triển đầy đủ, bạn sẽ quay trở lại SUT ban đầu và bổ sung nó về mặt Rollđầu vào.

Gợi ý của Người trợ giúp kiểm tra không nhất thiết ngụ ý tính ngẫu nhiên - đó chỉ là một cách để làm cho bài kiểm tra dễ đọc hơn.

Một cách khác để tiếp cận và mô hình hóa đầu vào theo các Rolltrường hợp sẽ là giới thiệu Trình tạo dữ liệu thử nghiệm .

Đỏ / Xanh / Tái cấu trúc là một quá trình gồm ba giai đoạn

Mặc dù tôi đồng ý với suy nghĩ chung rằng (nếu bạn có đủ kinh nghiệm về TDD), bạn không cần phải tuân thủ TDD một cách chặt chẽ, tôi nghĩ rằng đó là lời khuyên khá kém trong trường hợp tập thể dục Yahtzee. Mặc dù tôi không biết chi tiết về các quy tắc của Yahtzee, tôi thấy không có lý lẽ thuyết phục nào ở đây rằng bạn không thể tuân thủ chặt chẽ quy trình Đỏ / Xanh / Tái cấu trúc và vẫn đi đến một kết quả phù hợp.

Điều mà hầu hết mọi người ở đây dường như quên mất là giai đoạn thứ ba của quy trình Red / Green / Refactor. Đầu tiên bạn viết bài kiểm tra. Sau đó, bạn viết thực hiện đơn giản nhất vượt qua tất cả các bài kiểm tra. Sau đó, bạn tái cấu trúc.

Ở đây, ở trạng thái thứ ba này, bạn có thể mang tất cả các kỹ năng chuyên nghiệp của mình. Đây là nơi bạn được phép phản ánh về mã.

Tuy nhiên, tôi nghĩ rằng đó là một sự đồng thuận để nói rằng bạn chỉ nên "Viết điều đơn giản nhất có thể không hoàn toàn bản lĩnh và rõ ràng là không chính xác mà hoạt động". Nếu bạn (nghĩ rằng bạn) biết đủ về việc thực hiện trước đó, thì mọi thứ thiếu giải pháp hoàn chỉnh sẽ rõ ràng là không chính xác . Theo như lời khuyên, thì điều này khá vô dụng với người mới.

Điều thực sự nên xảy ra là nếu bạn có thể làm cho tất cả các bài kiểm tra vượt qua với việc triển khai rõ ràng không chính xác , đó là phản hồi mà bạn nên viết một bài kiểm tra khác .

Thật đáng ngạc nhiên khi tần suất thực hiện dẫn bạn đến một triển khai hoàn toàn khác so với lần đầu tiên bạn nghĩ đến. Đôi khi, sự thay thế phát triển như thế có thể tốt hơn so với kế hoạch ban đầu của bạn.

Rigor là một công cụ học tập

Thật có ý nghĩa khi gắn bó với các quy trình nghiêm ngặt như Red / Green / Refactor miễn là người ta đang học. Nó buộc người học phải có kinh nghiệm với TDD không chỉ khi nó dễ, mà cả khi nó khó.

Chỉ khi bạn đã thành thạo tất cả các phần khó, bạn mới có thể đưa ra quyết định sáng suốt về việc khi nào đi chệch khỏi con đường 'thật'. Đó là khi bạn bắt đầu hình thành con đường của riêng bạn.


'người mới làm quen TDD ở đây, với tất cả những hiểu lầm thông thường về việc thử nó. Thật thú vị nếu bạn có thể làm cho tất cả các bài kiểm tra vượt qua với một triển khai rõ ràng không chính xác, đó là phản hồi mà bạn nên viết một bài kiểm tra khác. Có vẻ như là một cách tốt để giải quyết nhận thức rằng việc thử nghiệm các triển khai "bản lĩnh" là công việc bận rộn không cần thiết.
shambulator

1
Ồ, cảm ơn bạn. Tôi thực sự sợ hãi trước xu hướng của mọi người khi nói với những người mới bắt đầu trong TDD (hoặc bất kỳ môn học nào) "đừng lo lắng về các quy tắc, chỉ cần làm những gì cảm thấy tốt nhất". Làm thế nào bạn có thể biết những gì cảm thấy tốt nhất khi bạn không có kiến ​​thức hoặc kinh nghiệm? Tôi cũng muốn đề cập đến nguyên tắc ưu tiên chuyển đổi hoặc mã đó sẽ trở nên chung chung hơn khi các thử nghiệm trở nên cụ thể hơn. những người ủng hộ TDD khó tính nhất như chú bob sẽ không đứng sau khái niệm "chỉ cần thêm một câu lệnh if mới cho mỗi bài kiểm tra".
sara

41

Từ chối trách nhiệm, đây là TDD khi tôi thực hành nó và, như Kilian khéo léo chỉ ra, tôi sẽ cảnh giác với bất cứ ai đề xuất rằng có một cách đúng để thực hành nó. Nhưng có lẽ nó sẽ giúp bạn ...

Trước hết, điều đơn giản nhất bạn có thể làm để vượt qua bài kiểm tra của mình là:

public bool IsFullHouse(int roll1, int roll2, int roll3, int roll4, int roll5)
{
    return true;
}

Điều này rất có ý nghĩa vì không phải vì một số thực hành TDD, mà bởi vì từ ngữ khó trong tất cả những nghĩa đen đó không thực sự là một ý tưởng tốt. Một trong những điều khó khăn nhất để quẩn quanh với TDD là đó không phải là một chiến lược thử nghiệm toàn diện - đó là một cách để bảo vệ chống lại hồi quy và đánh dấu tiến trình trong khi giữ cho mã đơn giản. Đó là một chiến lược phát triển và không phải là một chiến lược thử nghiệm.

Lý do tôi đề cập đến sự khác biệt này là nó giúp hướng dẫn những bài kiểm tra bạn nên viết. Câu trả lời cho "tôi nên viết bài kiểm tra nào?" là "bất cứ bài kiểm tra nào bạn cần để lấy mã theo cách bạn muốn." Hãy nghĩ về TDD như một cách giúp bạn trêu chọc các thuật toán và lý do về mã của bạn. Vì vậy, với bài kiểm tra của bạn và triển khai "đơn giản xanh" của tôi, bài kiểm tra nào tiếp theo? Chà, bạn đã thiết lập một cái gì đó là một ngôi nhà đầy đủ, vậy khi nào nó không phải là một ngôi nhà đầy đủ?

public void Returns_true_when_roll_is_full_house()
{
    FullHouseTester sut = new FullHouseTester();
    var actual = sut.IsFullHouse(1, 2, 3, 4, 5);

    Assert.IsFalse(actual);
}

Bây giờ bạn phải tìm ra một số cách để phân biệt giữa hai trường hợp thử nghiệm có ý nghĩa . Cá nhân tôi đã giải quyết một chút thông tin để làm rõ "làm điều đơn giản nhất để vượt qua bài kiểm tra" và nói "làm điều đơn giản nhất để làm cho bài kiểm tra vượt qua sự thực thi của bạn." Viết các bài kiểm tra thất bại là lý do để bạn thay đổi mã, vì vậy khi bạn viết mỗi bài kiểm tra, bạn nên tự hỏi "mã của tôi không làm gì mà tôi muốn nó làm gì và làm thế nào tôi có thể phơi bày sự thiếu sót đó?" Nó cũng có thể giúp bạn làm cho mã của bạn mạnh mẽ và xử lý các trường hợp cạnh. Bạn làm gì nếu một người gọi đầu vào vô nghĩa?

public void Returns_true_when_roll_is_full_house()
{
    FullHouseTester sut = new FullHouseTester();
    var actual = sut.IsFullHouse(-1, -2, -3, -4, -5);

    //I dunno - throw exception, return false, etc, whatever you think it should do....
}

Tóm lại, nếu bạn đang kiểm tra mọi sự kết hợp của các giá trị, bạn gần như chắc chắn đã làm sai (và có khả năng kết thúc bằng một vụ nổ kết hợp của các điều kiện). Khi nói đến TDD, bạn nên viết số lượng tối thiểu các trường hợp thử nghiệm cần thiết để có được thuật toán bạn muốn. Bất kỳ bài kiểm tra nào khác mà bạn viết sẽ bắt đầu màu xanh lá cây và do đó trở thành tài liệu, về bản chất, và không hoàn toàn là một phần của quy trình TDD. Bạn sẽ chỉ viết thêm các trường hợp kiểm tra TDD nếu các yêu cầu thay đổi hoặc lỗi được đưa ra, trong trường hợp đó, bạn sẽ ghi lại sự thiếu hụt bằng một bài kiểm tra và sau đó vượt qua.

Cập nhật:

Tôi đã bắt đầu điều này như một bình luận để đáp lại cập nhật của bạn, nhưng nó đã bắt đầu khá lâu ...

Tôi muốn nói rằng vấn đề không phải là sự tồn tại của chữ, thời kỳ, mà với điều 'đơn giản nhất' là điều kiện gồm 5 phần. Khi bạn nghĩ về nó, một điều kiện 5 phần thực sự khá phức tạp. Nó sẽ được sử dụng phổ biến trong các bước từ màu đỏ sang màu xanh lá cây và sau đó để trừu tượng chúng thành các hằng số trong bước tái cấu trúc hoặc nếu không thì khái quát hóa chúng trong một bài kiểm tra sau.

Trong hành trình của riêng tôi với TDD, tôi nhận ra rằng có một sự khác biệt quan trọng cần được thực hiện - thật không tốt khi nhầm lẫn giữa "đơn giản" và "khó hiểu". Đó là, khi tôi bắt đầu, tôi đã xem mọi người làm TDD và tôi nghĩ rằng "họ chỉ đang làm điều ngu ngốc nhất có thể để làm các bài kiểm tra vượt qua" và tôi đã bắt chước điều đó một lúc, cho đến khi tôi nhận ra rằng "đơn giản" là khác biệt hơn là "sự khó hiểu". Đôi khi chúng trùng nhau, nhưng thường thì không.

Vì vậy, xin lỗi nếu tôi cho ấn tượng rằng sự tồn tại của chữ là vấn đề - không phải vậy. Tôi muốn nói rằng sự phức tạp của điều kiện với 5 mệnh đề là vấn đề. Màu đỏ-xanh đầu tiên của bạn chỉ có thể là "trở về đúng" bởi vì điều đó thực sự đơn giản (và khó hiểu, bởi sự trùng hợp ngẫu nhiên). Trường hợp thử nghiệm tiếp theo, với (1, 2, 3, 4, 5) sẽ phải trả về false và đây là lúc bạn bắt đầu bỏ lại "obtuse". Bạn phải tự hỏi "tại sao (1, 1, 1, 2, 2) là một ngôi nhà đầy đủ và (1, 2, 3, 4, 5) không?" Điều đơn giản nhất bạn có thể nghĩ ra có thể là một phần tử có phần tử thứ tự 5 hoặc phần tử thứ hai 2 và phần tử thứ hai không có. Những điều đó đơn giản, nhưng chúng cũng (không cần thiết) trở nên khó hiểu. Điều bạn thực sự muốn lái xe là "họ có bao nhiêu số giống nhau?" Vì vậy, bạn có thể vượt qua bài kiểm tra thứ hai bằng cách kiểm tra xem liệu có lặp lại hay không. Trong một lần lặp lại, bạn có một ngôi nhà đầy đủ, và trong một ngôi nhà khác bạn không có. Bây giờ bài kiểm tra đã qua và bạn viết một trường hợp thử nghiệm khác có lặp lại nhưng không phải là một ngôi nhà đầy đủ để tinh chỉnh thêm thuật toán của bạn.

Bạn có thể hoặc không thể làm điều này với nghĩa đen khi bạn đi, và nó tốt nếu bạn làm. Nhưng ý tưởng chung đang phát triển thuật toán của bạn 'một cách hữu cơ' khi bạn thêm nhiều trường hợp.


Tôi đã cập nhật câu hỏi của mình để thêm một số thông tin về lý do tại sao tôi bắt đầu với cách tiếp cận theo nghĩa đen.
Kristof Claes

9
Đây là một câu trả lời tuyệt vời.
Tallseth

1
Cảm ơn bạn rất nhiều vì câu trả lời chu đáo và giải thích tốt của bạn. Nó thực sự có ý nghĩa rất nhiều bây giờ khi tôi nghĩ về nó.
Kristof Claes

1
Kiểm tra kỹ lưỡng không có nghĩa là kiểm tra mọi sự kết hợp ... Điều đó thật ngớ ngẩn. Đối với trường hợp cụ thể này, hãy lấy một ngôi nhà đầy đủ cụ thể hoặc hai và một vài ngôi nhà không đầy đủ. Ngoài ra, bất kỳ kết hợp đặc biệt nào có thể gây rắc rối (ví dụ: 5 loại).
Schleis

3
+1 Các nguyên tắc đằng sau câu trả lời này được mô tả bởi Tiền đề ưu tiên chuyển đổi của Robert C. Martin Cleancoder.posterous.com/the-transatures-p Warriority
Mark Seemann

5

Kiểm tra năm giá trị theo nghĩa đen cụ thể trong một kết hợp cụ thể không phải là "đơn giản nhất" đối với bộ não đang bị sốt của tôi. Nếu giải pháp cho một vấn đề thực sự rõ ràng (tính xem bạn có chính xác ba và hai chính xác bất kỳ giá trị nào không ), thì bằng mọi cách hãy tiếp tục và mã hóa giải pháp đó, và viết một số thử nghiệm rất khó có thể thỏa mãn với số lượng mã bạn đã viết (nghĩa là các nghĩa đen khác nhau và các đơn đặt hàng khác nhau của bộ ba và nhân đôi).

Tối đa TDD thực sự là công cụ, không phải niềm tin tôn giáo. Quan điểm của họ là giúp bạn viết mã chính xác, nhanh chóng. Nếu một câu châm ngôn rõ ràng cản trở điều đó, chỉ cần nhảy về phía trước để chuyển sang bước tiếp theo. Sẽ có rất nhiều bit không rõ ràng trong dự án của bạn, nơi bạn có thể áp dụng nó.


5

Câu trả lời của Erik là tuyệt vời, nhưng tôi nghĩ rằng tôi có thể chia sẻ một mẹo trong bài kiểm tra viết.

Bắt đầu với bài kiểm tra này:

[Test]
public void FullHouseReturnsTrue()
{
    var pairNum = AnyDiceValue();
    var trioNum = AnyDiceValue();

    Assert.That(sut.IsFullHouse(trioNum, pairNum, trioNum, pairNum, trioNum));
}

Bài kiểm tra này thậm chí còn tốt hơn nếu bạn tạo một Rolllớp thay vì vượt qua 5 thông số:

[Test]
public void FullHouseReturnsTrue()
{
    var roll = AnyFullHouse();

    Assert.That(sut.IsFullHouse(roll));
}

Điều đó mang lại cho việc thực hiện này:

public bool IsFullHouse(Roll toCheck)
{
    return true;
}

Sau đó viết bài kiểm tra này:

[Test]
public void StraightReturnsFalse()
{
    var roll = AnyStraight();

    Assert.That(sut.IsFullHouse(roll), Is.False);
}

Khi đã qua, hãy viết cái này:

[Test]
public void ThreeOfAKindReturnsFalse()
{
    var roll = AnyStraight();

    Assert.That(sut.IsFullHouse(roll), Is.False);
}

Sau đó, tôi cá rằng bạn không cần phải viết thêm nữa (có thể là hai cặp, hoặc có thể là yahtzee, nếu bạn nghĩ đó không phải là một ngôi nhà đầy đủ).

Rõ ràng, thực hiện bất kỳ phương pháp nào của bạn để trả lại Rolls ngẫu nhiên đáp ứng phê bình của bạn.

Có một vài lợi ích cho phương pháp này:

  • Bạn không cần phải viết một bài kiểm tra với mục đích duy nhất là ngăn bạn khỏi bị mắc kẹt trên các giá trị cụ thể
  • Các bài kiểm tra truyền đạt ý định của bạn thực sự độc đáo (mã của bài kiểm tra đầu tiên hét lên "bất kỳ ngôi nhà đầy đủ nào cũng trở thành sự thật")
  • nó giúp bạn nhanh chóng giải quyết vấn đề
  • đôi khi nó sẽ nhận thấy những trường hợp bạn không nghĩ đến

Nếu bạn thực hiện phương pháp này, bạn sẽ cần cải thiện các thông điệp tường trình của mình trong các câu lệnh Assert.That. Nhà phát triển cần xem đầu vào nào gây ra lỗi.
Bringer128

Điều này không tạo ra một tình huống khó xử gà hay trứng? Khi bạn triển khai AnyFullHouse (cũng sử dụng TDD), bạn có cần IsFullHouse để xác minh tính đúng đắn của nó không? Cụ thể, nếu AnyFullHouse có lỗi, lỗi đó có thể được sao chép trong IsFullHouse.
tượng sáp

AnyFullHouse () là một phương thức trong trường hợp thử nghiệm. Bạn có thường TDD trường hợp thử nghiệm của bạn? Không. Ngoài ra, việc tạo ra một ví dụ ngẫu nhiên của một ngôi nhà đầy đủ (hoặc bất kỳ cuộn nào khác) sẽ đơn giản hơn nhiều so với việc kiểm tra sự tồn tại của nó. Tất nhiên, nếu thử nghiệm của bạn có lỗi, nó có thể được sao chép trong mã sản xuất. Điều đó đúng với mọi thử nghiệm mặc dù.
Tallseth

AnyFullHouse là một phương thức "trợ giúp" trong trường hợp thử nghiệm. Nếu họ nói chung là đủ phương pháp trợ giúp được thử nghiệm quá!
Đánh dấu Hurd

Có nên IsFullHousethực sự trở lại truenếu pairNum == trioNum ?
đệ quy.ninja

2

Tôi có thể nghĩ về hai cách chính mà tôi xem xét khi thử nghiệm điều này;

  1. Thêm "một số" trường hợp thử nghiệm khác (~ 5) của bộ nhà đầy đủ hợp lệ và cùng số lượng sai lệch dự kiến ​​({1, 1, 2, 3, 3} là một trường hợp tốt. Hãy nhớ rằng 5 ví dụ có thể là được công nhận là "3 cùng một cặp" do thực hiện không chính xác). Phương pháp này giả định rằng nhà phát triển không chỉ cố gắng vượt qua các bài kiểm tra, mà thực sự thực hiện nó đúng.

  2. Kiểm tra tất cả các bộ xúc xắc có thể (chỉ có 252 bộ khác nhau). Tất nhiên, điều này giả định rằng bạn có một số cách để biết câu trả lời dự kiến ​​là gì (trong thử nghiệm này được gọi là oracle.) Đây có thể là một triển khai tham chiếu của cùng chức năng hoặc con người. Nếu bạn muốn thực sự nghiêm ngặt, có thể đáng để tự mã hóa từng kết quả mong đợi.

Khi điều đó xảy ra, tôi đã viết một AI Yahtzee một lần, tất nhiên phải biết các quy tắc. Bạn có thể tìm thấy mã cho phần đánh giá điểm ở đây , xin lưu ý rằng việc triển khai dành cho phiên bản Scandinavi (Yatzy) và việc triển khai của chúng tôi giả định rằng súc sắc được đưa ra theo thứ tự được sắp xếp.


Câu hỏi đáng giá triệu đô la là, bạn đã lấy được AI Yahtzee bằng TDD thuần túy chưa? Đặt cược của tôi là bạn không thể; bạn phải sử dụng kiến ​​thức về miền, theo định nghĩa là không mù :)
Andres F.

Vâng, tôi đoán bạn đúng. Đây là một vấn đề chung với TDD, rằng các trường hợp thử nghiệm cần đầu ra dự kiến ​​trừ khi bạn chỉ muốn kiểm tra các sự cố không mong muốn và các ngoại lệ chưa được xử lý.
ansjob

0

Ví dụ này thực sự bỏ lỡ điểm. Chúng ta đang nói về một chức năng đơn giản ở đây không phải là một thiết kế phần mềm. Có một chút phức tạp? vâng, vì vậy bạn phá vỡ nó. Và bạn tuyệt đối không kiểm tra mọi đầu vào có thể có từ 1, 1, 1, 1, 1 đến 6, 6, 6, 6, 6, 6. Hàm trong câu hỏi không yêu cầu thứ tự, chỉ là sự kết hợp, cụ thể là AAABB.

Bạn không cần 200 bài kiểm tra logic riêng biệt. Bạn có thể sử dụng một bộ ví dụ. Gần như bất kỳ ngôn ngữ lập trình nào cũng có một ngôn ngữ được tích hợp sẵn:

Set set;
set.add(a);
set.add(b);
set.add(c);
set.add(d);
set.add(e);

if(set.size() == 2) { // means we *must* be of the form AAAAB or AAABB.
    if(a==b==c==d) // eliminate AAAAB
        return false;
    else
        return true;
}
return false;

Và nếu bạn nhận được đầu vào không phải là cuộn Yahtzee hợp lệ, bạn nên ném như không có ngày mai.

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.