Khi nào bạn viết mã "thực" trong TDD?

johnny 19/08/2017. 11 answers, 20.464 views
tdd

Tất cả các ví dụ tôi đã đọc và thấy trên video đào tạo đều có các ví dụ đơn giản. Nhưng những gì tôi không thấy nếu làm thế nào tôi làm mã "thực" sau khi tôi nhận được màu xanh lá cây. Đây có phải là phần "Refactor" không?

Nếu tôi có một đối tượng khá phức tạp với một phương pháp phức tạp, và tôi viết bài kiểm tra của tôi và tối thiểu để làm cho nó vượt qua (sau khi nó lần đầu tiên thất bại, Red). Khi nào tôi quay lại và viết mã thực? Và tôi viết bao nhiêu mã thực sự trước khi thử lại? Tôi đoán rằng cái cuối cùng là trực giác hơn.

Edit: Cảm ơn tất cả những ai đã trả lời. Tất cả các câu trả lời của bạn đã giúp tôi vô cùng. Dường như có những ý tưởng khác nhau về những gì tôi đã hỏi hoặc bối rối, và có thể có, nhưng những gì tôi hỏi là, tôi nói rằng tôi có đơn xin xây trường học.

Trong thiết kế của tôi, tôi có một kiến ​​trúc mà tôi muốn bắt đầu, Câu chuyện của người dùng, v.v. Từ đây, tôi lấy những Câu chuyện của người dùng đó và tôi tạo một bài kiểm tra để kiểm tra Câu chuyện của người dùng. Người dùng nói, Chúng tôi có người đăng ký học và trả lệ phí đăng ký. Vì vậy, tôi nghĩ về một cách để làm cho thất bại. Trong khi làm như vậy tôi thiết kế một lớp thử nghiệm cho lớp X (có thể là sinh viên), mà sẽ thất bại. Sau đó tôi tạo lớp "Sinh viên". Có lẽ "Trường học" tôi không biết.

Nhưng, trong mọi trường hợp, Design TD đang buộc tôi phải suy nghĩ qua câu chuyện. Nếu tôi có thể làm một bài kiểm tra thất bại, tôi biết tại sao nó thất bại, nhưng điều này giả định rằng tôi có thể làm cho nó vượt qua. Đó là về thiết kế.

Tôi thích điều này để suy nghĩ về đệ quy. Đệ quy không phải là một khái niệm khó. Thật khó để thực sự theo dõi nó trong đầu bạn, nhưng trong thực tế, phần khó nhất là biết, khi đệ quy "phá vỡ", khi dừng lại (ý kiến ​​của tôi, tất nhiên.) Vì vậy, tôi phải suy nghĩ về những gì dừng lại đệ quy đầu tiên. Nó chỉ là một sự tương tự không hoàn hảo, và nó giả định rằng mỗi lần lặp đệ quy là một "vượt qua". Một lần nữa, chỉ là một ý kiến.

Trong quá trình thực hiện, trường học khó thấy hơn. Các sổ cái số và ngân hàng là "dễ" theo nghĩa bạn có thể sử dụng số học đơn giản. Tôi có thể thấy dấu + b và trả về 0, v.v. Trong trường hợp hệ thống của mọi người, tôi phải suy nghĩ kỹ hơn về cách implement điều đó. Tôi có khái niệm về thất bại, vượt qua, refactor (chủ yếu là vì nghiên cứu và câu hỏi này.)

Những gì tôi không biết là dựa trên sự thiếu kinh nghiệm, theo ý kiến ​​của tôi. Tôi không biết làm thế nào để không đăng ký một học sinh mới. Tôi không biết làm thế nào để không ai đó gõ vào họ và nó được lưu vào cơ sở dữ liệu. Tôi biết cách tạo +1 cho phép toán đơn giản, nhưng với các thực thể như một người, tôi không biết liệu tôi có đang kiểm tra xem liệu tôi có lấy lại một ID duy nhất của cơ sở dữ liệu hay cái gì khác không khi ai đó nhập tên cơ sở dữ liệu hoặc cả hai hoặc không.

Hoặc, có lẽ điều này cho thấy tôi vẫn còn bối rối.

5 Comments
187 hobbs 25/07/2017
Sau khi người TDD về nhà vào ban đêm.
14 Goyo 25/07/2017
Tại sao bạn nghĩ rằng mã bạn viết là không có thật?
2 johnny 26/07/2017
@RubberDuck Nhiều hơn các câu trả lời khác đã làm. Tôi chắc rằng tôi sẽ sớm nhắc đến nó. Nó vẫn là loại người nước ngoài, nhưng tôi sẽ không từ bỏ nó. Những gì bạn nói có ý nghĩa. Tôi chỉ cố gắng làm cho nó có ý nghĩa trong bối cảnh của tôi hoặc một ứng dụng kinh doanh thông thường. Có lẽ một hệ thống kiểm kê hoặc tương tự. Tôi phải xem xét nó. Tôi rất biết ơn thời gian của bạn. Cảm ơn.
1 Edmund Reed 26/07/2017
Các câu trả lời đã chạm vào móng trên đầu, nhưng miễn là tất cả các bài kiểm tra của bạn đang trôi qua, và bạn không cần bất kỳ bài kiểm tra / chức năng mới nào, có thể giả sử mã bạn đã hoàn thành, thanh linting.
3 Borjab 26/07/2017
Có một giả định trong câu hỏi có thể có vấn đề trong "Tôi có một đối tượng khá phức tạp với một phương thức phức tạp". Trong TDD bạn viết các bài kiểm tra đầu tiên để bắt đầu với một mã khá đơn giản. Điều này sẽ buộc bạn phải viết mã một cấu trúc thử nghiệm thân thiện sẽ cần phải được mô-đun. Vì vậy, hành vi phức tạp sẽ được tạo ra bằng cách kết hợp các đối tượng đơn giản hơn. Nếu bạn kết thúc với một đối tượng hoặc phương thức khá phức tạp thì khi bạn cấu trúc lại

11 Answers


RubberDuck 27/07/2017.

Nếu tôi có một đối tượng khá phức tạp với một phương pháp phức tạp, và tôi viết bài kiểm tra của tôi và tối thiểu để làm cho nó vượt qua (sau khi nó lần đầu tiên thất bại, Red). Khi nào tôi quay lại và viết mã thực? Và tôi viết bao nhiêu mã thực sự trước khi thử lại? Tôi đoán rằng cái cuối cùng là trực giác hơn.

Bạn không "quay lại" và viết "mã thực". Đó là tất cả các mã thực. Những gì bạn làm là quay trở lại và thêm một thử nghiệm khác forces bạn phải change mã của mình để thực hiện kiểm tra mới.

Bạn viết bao nhiêu mã trước khi thử lại? Không ai. Bạn viết zero mã mà không có một thử nghiệm thất bại forces bạn phải viết nhiều mã hơn.

Nhận thấy mẫu?

Hãy xem qua một ví dụ đơn giản khác với hy vọng rằng nó sẽ giúp ích.

 Assert.Equal("1", FizzBuzz(1)); 

Dễ dàng peazy.

 public String FizzBuzz(int n) {
    return 1.ToString();
} 

Không phải những gì bạn gọi là mã thực, phải không? Chúng ta hãy thêm một bài kiểm tra có tác dụng thay đổi.

 Assert.Equal("2", FizzBuzz(2)); 

Chúng ta có thể làm điều gì đó ngớ ngẩn như if n == 1 , nhưng chúng ta sẽ bỏ qua giải pháp lành mạnh.

 public String FizzBuzz(int n) {
    return n.ToString();
} 

Mát mẻ. Điều này sẽ làm việc cho tất cả các số không FizzBuzz. Đầu vào tiếp theo nào sẽ buộc mã sản xuất thay đổi?

 Assert.Equal("Fizz", FizzBuzz(3));

public String FizzBuzz(int n) {
    if (n == 3)
        return "Fizz";
    return n.ToString();
} 

Và một lần nữa. Viết một bài kiểm tra mà sẽ không vượt qua được nêu ra.

 Assert.Equal("Fizz", FizzBuzz(6));

public String FizzBuzz(int n) {
    if (n % 3 == 0)
        return "Fizz";
    return n.ToString();
} 

Và bây giờ chúng ta đã bao gồm tất cả bội số của ba (không phải là bội số của năm, chúng ta sẽ lưu ý nó và quay lại).

Chúng tôi chưa viết một bài kiểm tra cho "Buzz", vì vậy hãy viết điều đó.

 Assert.Equal("Buzz", FizzBuzz(5));

public String FizzBuzz(int n) {
    if (n % 3 == 0)
        return "Fizz";
    if (n == 5)
        return "Buzz"
    return n.ToString();
} 

Và một lần nữa, chúng ta biết có một trường hợp khác mà chúng ta cần phải xử lý.

 Assert.Equal("Buzz", FizzBuzz(10));

public String FizzBuzz(int n) {
    if (n % 3 == 0)
        return "Fizz";
    if (n % 5 == 0)
        return "Buzz"
    return n.ToString();
} 

Và bây giờ chúng ta có thể xử lý tất cả bội số của 5 mà không phải là bội số của 3.

Cho đến thời điểm này, chúng tôi đã bỏ qua bước tái cấu trúc, nhưng tôi thấy một số trùng lặp. Hãy dọn dẹp nó ngay bây giờ.

 private bool isDivisibleBy(int divisor, int input) {
    return (input % divisor == 0);
}

public String FizzBuzz(int n) {
    if (isDivisibleBy(3, n))
        return "Fizz";
    if (isDivisibleBy(5, n))
        return "Buzz"
    return n.ToString();
} 

Mát mẻ. Bây giờ chúng tôi đã loại bỏ sự trùng lặp và tạo ra một chức năng được đặt tên tốt. Thử nghiệm tiếp theo chúng ta có thể viết là gì sẽ buộc chúng ta phải thay đổi mã? Vâng, chúng tôi đã tránh trường hợp số chia hết cho cả 3 và 5. Hãy viết ngay bây giờ.

 Assert.Equal("FizzBuzz", FizzBuzz(15));

public String FizzBuzz(int n) {
    if (isDivisibleBy(3, n) && isDivisibleBy(5, n))
        return "FizzBuzz";
    if (isDivisibleBy(3, n))
        return "Fizz";
    if (isDivisibleBy(5, n))
        return "Buzz"
    return n.ToString();
} 

Các bài kiểm tra vượt qua, nhưng chúng tôi có nhiều bản sao hơn. Chúng ta có các tùy chọn, nhưng tôi sẽ áp dụng "Extract Local Variable" một vài lần để chúng ta tái cấu trúc thay vì viết lại.

 public String FizzBuzz(int n) {

    var isDivisibleBy3 = isDivisibleBy(3, n);
    var isDivisibleBy5 = isDivisibleBy(5, n);

    if ( isDivisibleBy3 && isDivisibleBy5 )
        return "FizzBuzz";
    if ( isDivisibleBy3 )
        return "Fizz";
    if ( isDivisibleBy5 )
        return "Buzz"
    return n.ToString();
} 

Và chúng tôi đã đề cập đến mọi đầu vào hợp lý, nhưng đầu vào unreasonable thì sao? Điều gì sẽ xảy ra nếu chúng ta vượt qua 0 hoặc âm? Viết các trường hợp thử nghiệm đó.

 public String FizzBuzz(int n) {

    if (n < 1)
        throw new InvalidArgException("n must be >= 1);

    var isDivisibleBy3 = isDivisibleBy(3, n);
    var isDivisibleBy5 = isDivisibleBy(5, n);

    if ( isDivisibleBy3 && isDivisibleBy5 )
        return "FizzBuzz";
    if ( isDivisibleBy3 )
        return "Fizz";
    if ( isDivisibleBy5 )
        return "Buzz"
    return n.ToString();
} 

Điều này có bắt đầu trông giống như "mã thực" chưa? Quan trọng hơn, tại điểm nào nó dừng lại là "mã không thực" và chuyển đổi thành "thực"? Đó là một cái gì đó để suy ngẫm về ...

Vì vậy, tôi đã có thể làm điều này chỉ đơn giản bằng cách tìm kiếm một bài kiểm tra mà tôi biết sẽ không vượt qua ở mỗi bước, nhưng tôi đã có rất nhiều thực hành. Khi tôi làm việc, mọi thứ không đơn giản như thế này và tôi có thể không phải lúc nào cũng biết thử nghiệm nào sẽ gây ra thay đổi. Đôi khi tôi sẽ viết một bài kiểm tra và ngạc nhiên khi thấy nó đã trôi qua! Tôi khuyên bạn nên có thói quen tạo một "Danh sách kiểm tra" trước khi bạn bắt đầu. Danh sách kiểm tra này nên chứa tất cả các đầu vào "thú vị" mà bạn có thể nghĩ đến. Bạn có thể không sử dụng tất cả và bạn sẽ có khả năng thêm trường hợp khi bạn đi, nhưng danh sách này phục vụ như là một lộ trình. Danh sách kiểm tra của tôi cho FizzBuzz sẽ trông giống như thế này.

  • Tiêu cực
  • Số không
  • Một
  • Hai
  • Số ba
  • Bốn
  • Số năm
  • Sáu (bội số không nhỏ của 3)
  • Chín (3 bình phương)
  • Mười (bội số không nhỏ trong 5)
  • 15 (bội số của 3 & 5)
  • 30 (bội số không nhỏ của 3 & 5)
5 comments
3 maple_shaft♦ 27/07/2017
Nhận xét không dành cho thảo luận mở rộng; cuộc trò chuyện này đã được chuyển sang trò chuyện .
40 GManNickG 27/07/2017
Trừ khi tôi hoàn toàn hiểu nhầm câu trả lời này: "Chúng ta có thể làm điều gì đó ngớ ngẩn như n == 1, nhưng chúng ta sẽ bỏ qua giải pháp lành mạnh." - toàn bộ điều đó là ngớ ngẩn. Nếu bạn biết trước bạn muốn có một hàm <spec>, viết test cho <spec> và bỏ qua phần mà bạn viết các phiên bản rõ ràng là thất bại <spec>. Nếu bạn tìm thấy một lỗi trong <spec> thì chắc chắn: viết một bài kiểm tra đầu tiên để xác minh bạn có thể thực hiện nó trước khi sửa chữa và quan sát kiểm tra vượt qua sau khi sửa chữa. Nhưng không cần phải giả mạo tất cả các bước trung gian này.
15 user3791372 28/07/2017
Các ý kiến ​​chỉ ra những sai sót chính trong câu trả lời này và TDD nói chung đã được chuyển sang trò chuyện. Nếu bạn đang cân nhắc sử dụng TDD, vui lòng đọc 'trò chuyện'. Thật không may, các bình luận 'chất lượng' hiện bị ẩn trong một tải trò chuyện cho các sinh viên tương lai để đọc.
nbro 28/07/2017
Tôi sẽ chính xác hơn về nội dung của "danh sách kiểm tra" này, nếu bạn muốn cải thiện câu trả lời này. Tôi sẽ nói một cách rõ ràng về "các giá trị biên" và "phân vùng lớp".
2 hvd 30/07/2017
@GManNickG Tôi tin rằng điểm là để có được số tiền phải của các xét nghiệm. Viết các bài kiểm tra trước để dễ dàng bỏ qua những trường hợp đặc biệt nào cần được kiểm tra, dẫn đến các tình huống không được bao phủ đầy đủ trong các bài kiểm tra, hoặc về cơ bản tình huống tương tự được bao phủ vô số lần trong các bài kiểm tra. Nếu bạn có thể làm điều đó mà không có các bước trung gian này, tuyệt vời! Không phải tất cả mọi người có thể làm như vậy được nêu ra mặc dù, đó là một cái gì đó mà có thực hành.

GenericJon 24/07/2017.

Mã "thực" là mã bạn viết để thực hiện kiểm tra. Really . Nó đơn giản mà.

Khi mọi người nói về việc viết tối thiểu để làm bài kiểm tra màu xanh lá cây, điều đó chỉ có nghĩa là mã thực của bạn nên tuân theo nguyên tắc YAGNI .

Ý tưởng về bước tái cấu trúc chỉ là để làm sạch những gì bạn đã viết khi bạn hài lòng vì nó đáp ứng các yêu cầu.

Vì vậy, miễn là các bài kiểm tra mà bạn viết thực sự bao gồm các yêu cầu sản phẩm của bạn, một khi chúng được truyền thì mã hoàn tất. Hãy suy nghĩ về nó, nếu tất cả các yêu cầu kinh doanh của bạn có một bài kiểm tra và tất cả các bài kiểm tra đó là màu xanh lá cây, thì còn gì để viết nữa? (Được rồi, trong cuộc sống thực, chúng tôi không có xu hướng có phạm vi kiểm tra hoàn chỉnh, nhưng lý thuyết là âm thanh.)

5 comments
44 Derek Elkins 24/07/2017
Kiểm tra đơn vị không thể thực sự bao gồm các yêu cầu sản phẩm của bạn cho các yêu cầu thậm chí tầm thường tương đối. Tốt nhất, họ lấy mẫu không gian đầu vào-đầu ra và ý tưởng là bạn (chính xác) khái quát hóa không gian đầu vào-đầu ra đầy đủ. Tất nhiên, mã của bạn chỉ có thể là một switch lớn với một trường hợp cho mỗi bài kiểm tra đơn vị mà sẽ vượt qua tất cả các bài kiểm tra và thất bại cho bất kỳ đầu vào khác.
8 Taemyr 25/07/2017
@DerekElkins TDD yêu cầu kiểm tra không thành công. Không kiểm tra đơn vị không.
6 jonrsharpe 25/07/2017
@ DerekElkins đó là lý do tại sao bạn không chỉ viết các bài kiểm tra đơn vị, và cũng là lý do tại sao có một giả định chung rằng bạn đang cố gắng để làm cho một cái gì đó không chỉ giả nó!
35 Derek Elkins 25/07/2017
@jonrsharpe Bởi logic đó, tôi sẽ không bao giờ viết những triển khai tầm thường. Ví dụ trong ví dụ FizzBuzz trong câu trả lời của RubberDuck (chỉ sử dụng các bài kiểm tra đơn vị), việc thực hiện đầu tiên rõ ràng là "chỉ cần giả mạo nó". Sự hiểu biết của tôi về câu hỏi là sự phân đôi chính xác giữa việc viết mã mà bạn biết là không đầy đủ và mã mà bạn thực sự tin rằng sẽ thực hiện yêu cầu, "mã thực". "Công switch lớn" của tôi được dự định là một cực kỳ hợp lý của việc "viết tối thiểu để làm cho các thử nghiệm xanh". Tôi xem câu hỏi của OP là: ở đâu trong TDD là nguyên tắc tránh được công switch lớn này?
2 Luaan 25/07/2017
@ GenericJon Đó là một chút quá lạc quan trong kinh nghiệm của tôi :) Đối với một, có những người tận hưởng công việc lặp đi lặp lại mindless. Họ sẽ hạnh phúc hơn với một tuyên bố chuyển đổi khổng lồ hơn là với một "quyết định phức tạp". Và để mất việc, họ cần ai đó gọi họ bằng kỹ thuật (và họ có bằng chứng tốt hơn là thực sự mất cơ hội / tiền bạc của công ty!), Hoặc làm một cách đặc biệt tồi tệ. Sau khi tiếp tục bảo trì trên nhiều dự án như vậy, tôi có thể nói rằng rất dễ dàng cho mã rất ngây thơ để kéo dài trong nhiều thập kỷ, miễn là nó làm cho khách hàng hài lòng (và trả tiền).

Carl Raymond 24/07/2017.

Câu trả lời ngắn gọn là "mã thực" là mã mà làm cho kiểm tra vượt qua. Nếu bạn có thể làm bài kiểm tra của mình bằng một thứ khác ngoài mã thực, hãy thêm các bài kiểm tra khác!

Tôi đồng ý rằng rất nhiều hướng dẫn về TDD là đơn giản. Điều đó có tác dụng chống lại chúng. Một bài kiểm tra quá đơn giản cho một phương pháp, nói rằng, tính toán 3 + 8 thực sự không có sự lựa chọn nào khác ngoài tính toán 3 + 8 và so sánh kết quả. Điều đó làm cho nó trông giống như bạn sẽ chỉ được sao chép mã trên tất cả, và thử nghiệm đó là vô nghĩa, dễ bị lỗi thêm làm việc.

Khi bạn giỏi kiểm tra, điều đó sẽ thông báo cách bạn cấu trúc ứng dụng của mình và cách bạn viết mã của mình. Nếu bạn gặp khó khăn trong việc đưa ra các bài kiểm tra hợp lý, hữu ích, bạn có lẽ nên nghĩ lại thiết kế của mình một chút. Một hệ thống được thiết kế tốt là dễ dàng để kiểm tra - có nghĩa là các bài kiểm tra hợp lý dễ suy nghĩ và thực hiện.

Khi bạn viết các bài kiểm tra trước, hãy xem chúng không thành công, và sau đó viết mã mà làm cho chúng vượt qua, đó là một kỷ luật để đảm bảo rằng tất cả các mã của bạn có các bài kiểm tra tương ứng. Tôi không slavishly làm theo quy tắc đó khi tôi đang mã hóa; tôi thường viết các bài kiểm tra sau khi thực tế. Nhưng làm bài kiểm tra đầu tiên giúp giữ cho bạn trung thực. Với một số kinh nghiệm, bạn sẽ bắt đầu nhận thấy khi bạn đang mã hóa chính mình vào một góc, ngay cả khi bạn không viết bài kiểm tra đầu tiên.

4 comments
6 Steve Jessop 26/07/2017
Cá nhân, các bài kiểm tra tôi muốn viết sẽ được assertEqual(plus(3,8), 11) , không assertEqual(plus(3,8), my_test_implementation_of_addition(3,8)) . Đối với các trường hợp phức tạp hơn, bạn luôn tìm phương tiện chứng minh kết quả chính xác, other than tính toán động kết quả chính xác trong kiểm tra và kiểm tra bình đẳng.
Steve Jessop 26/07/2017
Vì vậy, đối với một cách thực sự ngớ ngẩn khi làm ví dụ này, bạn có thể chứng minh rằng plus(3,8) đã trả lại kết quả chính xác bằng cách trừ 3 từ nó, trừ 8 từ đó và kiểm tra kết quả bằng 0. Điều này rõ ràng tương đương với assertEqual(plus(3,8), 3+8) là một chút ngớ ngẩn, nhưng nếu đoạn code đang được thử nghiệm đang xây dựng một cái gì đó phức tạp hơn chỉ là một số nguyên, sau đó lấy kết quả và kiểm tra từng phần cho tính đúng đắn cách tiếp cận đúng. Ngoài ra, một cái gì đó như for (i=0, j=10; i < 10; ++i, ++j) assertEqual(plus(i, 10), j)
Steve Jessop 26/07/2017
... vì điều đó tránh được nỗi sợ lớn, đó là khi viết bài kiểm tra, chúng tôi sẽ phạm sai lầm tương tự về chủ đề "cách thêm 10" mà chúng tôi đã thực hiện trong mã trực tiếp. Vì vậy, bài kiểm tra cẩn thận tránh viết bất kỳ mã nào thêm 10 vào bất kỳ thứ gì, trong bài kiểm tra plus() có thể thêm 10 vào mọi thứ. Chúng tôi vẫn dựa vào các giá trị vòng lặp của các lập trình viên đã xác minh, tất nhiên.
3 Warbo 28/07/2017
Chỉ muốn chỉ ra rằng ngay cả khi bạn đang viết bài kiểm tra sau khi thực tế, nó vẫn là một ý tưởng tốt để xem chúng thất bại; tìm thấy một số phần của mã có vẻ quan trọng đối với bất kỳ thứ gì bạn đang làm việc, chỉnh sửa nó một chút (ví dụ: thay thế dấu + bằng - hoặc bất kỳ thứ gì), chạy thử nghiệm và xem chúng không thành công, hoàn tác thay đổi và xem chúng. Nhiều lần tôi đã thực hiện thử nghiệm này không thực sự thất bại, làm cho nó tồi tệ hơn vô ích: không chỉ là nó không kiểm tra bất cứ điều gì, nó cho tôi sự tự tin sai lầm rằng một cái gì đó đang được thử nghiệm!

Victor Cejudo 25/07/2017.

Đôi khi một số ví dụ về TDD có thể gây hiểu nhầm. Như những người khác đã chỉ ra trước đây, mã bạn viết để làm bài kiểm tra là mã thực.

Nhưng đừng nghĩ rằng mã thực sự xuất hiện như ma thuật. Bạn cần một sự hiểu biết tốt hơn về những gì bạn muốn đạt được và sau đó bạn cần phải chọn bài kiểm tra cho phù hợp, bắt đầu từ các trường hợp dễ nhất và các trường hợp góc.

Ví dụ, nếu bạn cần viết một lexer, bạn bắt đầu với chuỗi rỗng, sau đó với một loạt các khoảng trắng, sau đó là một số, sau đó với một số được bao quanh bởi khoảng trắng, sau đó là số sai, v.v ... Những biến đổi nhỏ này sẽ dẫn bạn đến các thuật toán đúng, nhưng bạn không nhảy từ trường hợp dễ nhất đến một trường hợp rất phức tạp được chọn ngu xuẩn để có được mã thực được thực hiện.

Bob Martin giải thích nó hoàn hảo ở đây .


CandiedOrange 25/07/2017.

Phần refactor được dọn sạch khi bạn mệt mỏi và muốn về nhà.

Khi bạn sắp thêm một đối tượng địa lý, phần cấu trúc lại là những gì bạn thay đổi trước bài kiểm tra tiếp theo. Bạn refactor mã để nhường chỗ cho tính năng mới. Bạn làm điều này khi bạn know tính năng mới đó sẽ là gì. Không phải khi bạn chỉ tưởng tượng ra nó.

Điều này có thể đơn giản như đổi tên GreetImpl thành GreetWorld trước khi bạn tạo một lớp GreetMom (sau khi thêm bài kiểm tra) để thêm một tính năng sẽ in "Xin chào mẹ".


graeme 27/07/2017.

Nhưng mã thực sự sẽ xuất hiện trong giai đoạn tái cấu trúc của giai đoạn TDD. Tức là mã phải là một phần của bản phát hành cuối cùng.

Kiểm tra nên được chạy mỗi khi bạn thực hiện một thay đổi.

Phương châm của vòng đời TDD sẽ là: RED REFACTOR

RED : Viết các bài kiểm tra

GREEN : Thực hiện một nỗ lực trung thực để lấy mã chức năng vượt qua các bài kiểm tra nhanh nhất có thể: mã trùng lặp, các biến có tên được đặt tên theo thứ tự cao nhất, v.v.

REFACTOR : Làm sạch mã, đặt tên đúng các biến. SẤY mã.

5 comments
5 mcottle 25/07/2017
Tôi biết những gì bạn đang nói về giai đoạn "Xanh" nhưng nó ngụ ý rằng các giá trị trả về dây cứng để làm cho các bài kiểm tra vượt qua có thể là thích hợp. Trong kinh nghiệm của tôi "Xanh" nên là một nỗ lực trung thực để làm cho mã làm việc để đáp ứng yêu cầu, nó có thể không hoàn hảo nhưng nó phải được hoàn thành và "shippable" như các nhà phát triển có thể quản lý trong một vượt qua đầu tiên. Tái cấu trúc có thể được thực hiện tốt nhất một thời gian sau đó sau khi bạn đã phát triển nhiều hơn và các vấn đề với lần truyền đầu tiên trở nên rõ ràng hơn và cơ hội để DRY xuất hiện.
graeme 25/07/2017
@mcottle tôi xem xét tất cả các phần của cùng một nhiệm vụ. làm cho nó được thực hiện, sau đó làm sạch nó lên. Việc tái cấu trúc thêm sẽ diễn ra khi thời gian trôi qua như là một phần của các nhiệm vụ khác.
1 Bryan Boettcher 25/07/2017
@mcottle: bạn có thể ngạc nhiên về việc có bao nhiêu triển khai của một kho lưu trữ chỉ có thể được mã hóa các giá trị trong codebase. :)
6 Kaz 25/07/2017
Tại sao tôi lại viết mã crap và dọn dẹp nó, khi tôi có thể quây quần tốt đẹp, mã chất lượng sản xuất gần như nhanh như tôi có thể gõ? :)
1 Kaz 27/07/2017
@TimothyTruckle Điều gì sẽ xảy ra nếu mất 50 phút để tìm ra sự thay đổi đơn giản nhất có thể, nhưng chỉ có 5 để tìm ra sự thay đổi đơn giản thứ hai có thể xảy ra? Chúng ta đi với đơn giản thứ hai hay tiếp tục tìm kiếm đơn giản nhất?

Timothy Truckle 27/07/2017.

Khi nào bạn viết mã "thực" trong TDD?

Giai đoạn red là nơi bạn write mã.

Trong giai đoạn refactoring , mục tiêu chính là delete mã.

Trong giai đoạn red bạn làm bất cứ điều gì để làm cho kỳ thi vượt qua as quick as possibleat any cost . Bạn hoàn toàn bỏ qua những gì bạn đã từng nghe nói về thực hành mã hóa tốt hoặc mẫu thiết kế giống nhau. Làm cho thử nghiệm màu xanh lá cây là tất cả những gì quan trọng.

Trong giai đoạn refactoring bạn dọn dẹp đống lộn xộn mà bạn vừa tạo ra. Bây giờ bạn đầu tiên nhìn xem thay đổi bạn vừa tạo ra là loại đầu tiên trong danh sách Ưu tiên chuyển đổi và nếu có bất kỳ sự sao chép mã nào bạn có thể loại bỏ hầu hết bằng cách áp dụng một mẫu thiết kế.

Cuối cùng, bạn cải thiện khả năng đọc bằng cách đổi tên mã định danh và trích xuất magic numbers và / hoặc chuỗi ký tự thành hằng số.


Nó không phải là red refactor, nó là red-green-refactor. - Rob Kinyon

Cảm ơn bạn đã chỉ ra điều này.

Vì vậy, nó là giai đoạn green , nơi bạn viết real code

Trong giai đoạn red bạn viết executable specification ...

2 comments
Rob Kinyon 27/07/2017
Nó không phải là red refactor, nó là red-green-refactor. Các "màu đỏ" là bạn lấy bộ thử nghiệm của bạn từ màu xanh lá cây (tất cả các bài kiểm tra vượt qua) để màu đỏ (một bài kiểm tra thất bại). "Xanh" là nơi bạn sloppily lấy bộ thử nghiệm của bạn từ màu đỏ (một thử nghiệm không thành công) để màu xanh lá cây (tất cả các bài kiểm tra vượt qua). "Refactor" là nơi bạn lấy mã của bạn và làm cho nó đẹp trong khi vẫn giữ tất cả các kiểm tra đi qua.
Timothy Truckle 27/07/2017
@RobKinyon Cảm ơn, đã cập nhật câu trả lời.

Robert Andrzejuk 27/07/2017.

Bạn đang viết Real Code trong toàn bộ thời gian.

Tại mỗi bước Bạn đang viết mã để đáp ứng các điều kiện mà mã của bạn sẽ đáp ứng cho người gọi trong tương lai của mã của bạn (có thể là bạn hay không ...).

Bạn nghĩ rằng Bạn không viết mã hữu ích ( real ), bởi vì trong một thời điểm Bạn có thể cấu trúc lại nó.

Mã-Refactoring là quá trình tái cơ cấu mã máy tính hiện tại - thay đổi bao thanh toán — mà không thay đổi hành vi bên ngoài của nó.

Điều này có nghĩa là mặc dù bạn đang thay đổi mã, các điều kiện mã được satisified, vẫn không thay đổi. Và kiểm tra ( tests ) Bạn đã triển khai để xác minh Mã của bạn đã có sẵn để xác minh xem các sửa đổi của bạn có thay đổi gì không. Vậy mã bạn viết toàn bộ thời gian ở đó, chỉ theo một cách khác.

Một lý do khác Bạn có thể nghĩ rằng đó không phải là mã thực sự, là bạn đang làm ví dụ mà chương trình kết thúc có thể đã được bạn thấy trước. Điều này rất tốt, vì nó cho thấy Bạn có kiến ​​thức về domain Bạn đang lập trình.
Nhưng nhiều lần các lập trình viên đang ở trong một domain new , unknown đến chúng. Họ không biết kết quả cuối cùng sẽ là gì và TDD là technique viết từng bước chương trình, ghi lại knowledge của chúng tôi về cách hệ thống này hoạt động và xác minh rằng mã của chúng tôi hoạt động theo cách đó.

Khi tôi đọc Sách (*) trên TDD, đối với tôi, tính năng quan trọng nhất nổi bật là: danh sách TODO. Nó cho tôi thấy rằng, TDD cũng là một kỹ thuật giúp các nhà phát triển tập trung vào một điều tại một thời điểm. Vì vậy, đây cũng là một câu trả lời cho câu hỏi của bạn aboout How much Real code to write ? Tôi sẽ nói đủ mã để tập trung vào 1 điều tại một thời điểm.

(*) "Thử nghiệm phát triển theo định hướng: Ví dụ" của Kent Beck

1 comments
2 Robert Andrzejuk 27/07/2017
"Thử nghiệm phát triển theo định hướng: Ví dụ" của Kent Beck

Zenilogix 31/07/2017.

Bạn không viết mã để làm cho các bài kiểm tra của bạn thất bại.

Bạn viết các bài kiểm tra của bạn để xác định thành công sẽ như thế nào, tất cả những gì ban đầu sẽ thất bại vì bạn chưa viết mã sẽ vượt qua.

Toàn bộ điểm về viết các bài kiểm tra đầu tiên không thành công là làm hai việc:

  1. Bao gồm tất cả các trường hợp - tất cả các trường hợp danh nghĩa, tất cả các trường hợp cạnh, v.v.
  2. Xác thực kiểm tra của bạn. Nếu bạn chỉ nhìn thấy chúng vượt qua, làm thế nào bạn có thể chắc chắn rằng họ sẽ báo cáo một cách đáng tin cậy khi một sự cố xảy ra?

Điểm đằng sau red-green-refactor là viết các test chính xác trước tiên cho bạn biết rằng mã bạn viết để vượt qua các test là chính xác, và cho phép bạn cấu trúc lại với sự tự tin rằng các test của bạn sẽ thông báo cho bạn ngay khi một cái gì đó phá vỡ, vì vậy bạn ngay lập tức có thể quay trở lại và sửa chữa nó.

Theo kinh nghiệm của riêng tôi (C # /. NET), thử nghiệm thuần túy đầu tiên là một chút lý tưởng không thể đạt được, bởi vì bạn không thể biên dịch cuộc gọi đến một phương thức chưa tồn tại. Vì vậy, "thử nghiệm đầu tiên" thực sự là về mã hóa giao diện và triển khai stubbing đầu tiên, sau đó viết các bài kiểm tra chống lại các cuống (mà ban đầu sẽ thất bại) cho đến khi cuống được xác thịt đúng cách. Tôi không bao giờ viết "không mã", chỉ cần xây dựng từ cuống.


Zan Lynx 27/07/2017.

Tôi nghĩ rằng bạn có thể nhầm lẫn giữa các bài kiểm tra đơn vị và kiểm tra tích hợp. Tôi tin rằng cũng có thể có các bài kiểm tra chấp nhận, nhưng điều đó phụ thuộc vào quá trình của bạn.

Một khi bạn đã thử nghiệm tất cả các "đơn vị" nhỏ sau đó bạn kiểm tra chúng tất cả các lắp ráp, hoặc "tích hợp". Đó thường là toàn bộ chương trình hoặc thư viện.

Trong mã mà tôi đã viết tích hợp kiểm tra một thư viện với các chương trình thử nghiệm khác nhau mà đọc dữ liệu và đưa nó vào thư viện, sau đó kiểm tra kết quả. Sau đó, tôi làm điều đó với chủ đề. Sau đó, tôi làm điều đó với các chủ đề và ngã ba () ở giữa. Sau đó, tôi chạy nó và giết -9 sau 2 giây, sau đó tôi bắt đầu nó và kiểm tra chế độ phục hồi của nó. Tôi làm mờ nó. Tôi tra tấn nó bằng mọi cách.

Tất cả điều đó là CSONG thử nghiệm, nhưng tôi không có màn hình màu đỏ / xanh lá cây cho kết quả. Nó thành công, hoặc tôi đào qua vài nghìn dòng mã lỗi để tìm hiểu lý do.

Đó là nơi bạn kiểm tra "mã thực".

Và tôi chỉ nghĩ về điều này, nhưng có lẽ bạn không biết khi nào bạn phải làm bài kiểm tra viết đơn vị. Bạn đang thực hiện các bài kiểm tra viết đơn vị khi các bài kiểm tra của bạn thực hiện mọi thứ mà bạn đã chỉ định nó nên làm. Đôi khi bạn có thể mất theo dõi trong số tất cả các trường hợp xử lý lỗi và cạnh, vì vậy bạn có thể muốn thực hiện một nhóm thử nghiệm tốt đẹp của các bài kiểm tra đường dẫn hạnh phúc mà chỉ cần đi thẳng qua các thông số kỹ thuật.

1 comments
Peter Mortensen 27/07/2017
(của nó = sở hữu, nó = "nó là" hoặc "nó có". Xem ví dụ How to Use Its and It's .)

user3791372 27/07/2017.

Trong câu trả lời cho tiêu đề của câu hỏi: "Khi nào bạn viết mã" thực "trong TDD?", Câu trả lời là: "hầu như không bao giờ" hoặc "rất chậm".

Bạn âm thanh như một sinh viên, vì vậy tôi sẽ trả lời như thể tư vấn cho một sinh viên.

Bạn sẽ học được rất nhiều mã 'lý thuyết' và 'kỹ thuật'. Họ rất tuyệt vì đã dành thời gian cho các khóa học sinh viên đắt đỏ, nhưng rất ít lợi ích cho bạn rằng bạn không thể đọc trong một cuốn sách trong một nửa thời gian.

Công việc của một coder là chỉ để tạo mã. Mã hoạt động thực sự tốt. Đó là lý do tại sao bạn, coder lập kế hoạch mã trong tâm trí của bạn, trên giấy, trong một ứng dụng phù hợp, vv, và bạn có kế hoạch để làm việc xung quanh lỗ hổng có thể / lỗ trước bằng cách suy nghĩ hợp lý và sau đó trước khi mã hóa.

Nhưng bạn cần biết cách phá vỡ ứng dụng của mình để có thể thiết kế mã phong nha. Ví dụ, nếu bạn không biết về Little Bobby Table (xkcd 327), thì có thể bạn sẽ không làm sạch đầu vào của bạn trước khi làm việc với cơ sở dữ liệu, vì vậy bạn sẽ không thể bảo mật dữ liệu của bạn xung quanh khái niệm đó.

TDD chỉ là một luồng công việc được thiết kế để giảm thiểu các lỗi trong mã của bạn bằng cách tạo ra các thử nghiệm về những gì có thể xảy ra trước khi bạn mã hóa ứng dụng của mình vì mã hóa có thể gặp khó khăn về số mũ nhiều hơn bạn giới thiệu và bạn quên các lỗi mà bạn từng nghĩ đến. Một khi bạn nghĩ rằng bạn đã hoàn thành ứng dụng của bạn, bạn chạy các bài kiểm tra và bùng nổ, hy vọng lỗi được bắt gặp với các bài kiểm tra của bạn.

TDD không - như một số người tin rằng - viết một bài kiểm tra, làm cho nó đi qua với mã tối thiểu, viết một bài kiểm tra khác, nhận được rằng đi qua với mã tối thiểu, vv Thay vào đó, đó là một cách giúp bạn mã tự tin. Điều này lý tưởng của mã tái cấu trúc liên tục để làm cho nó làm việc với các bài kiểm tra là ngu ngốc, nhưng nó là một khái niệm tốt đẹp giữa các sinh viên bởi vì nó làm cho họ cảm thấy tuyệt vời khi họ thêm một tính năng mới và họ vẫn đang học cách mã ...

Xin vui lòng không rơi xuống cái bẫy này và xem vai trò của bạn về mã hóa cho những gì nó là - công việc của một coder là chỉ để sản xuất mã. Mã hoạt động thực sự tốt. Bây giờ, hãy nhớ rằng bạn sẽ có mặt trên đồng hồ với tư cách là một lập trình viên chuyên nghiệp và khách hàng của bạn sẽ không quan tâm nếu bạn đã viết 100.000 xác nhận hoặc 0. Họ chỉ muốn mã hoạt động. Thực sự tốt, trên thực tế.

5 comments
3 johnny 25/07/2017
Tôi thậm chí không gần gũi với một sinh viên, nhưng tôi đọc và cố gắng áp dụng các kỹ thuật tốt và chuyên nghiệp. Vì vậy, theo nghĩa đó, tôi là một "sinh viên". Tôi chỉ hỏi những câu hỏi rất cơ bản bởi vì đó là cách tôi. Tôi muốn biết chính xác lý do tại sao tôi đang làm những gì tôi đang làm. Trung tâm của vấn đề. Nếu tôi không hiểu, tôi không thích và bắt đầu đặt câu hỏi. Tôi cần phải biết tại sao, nếu tôi sẽ sử dụng nó. TDD có vẻ trực giác tốt theo một số cách như biết những gì bạn cần để tạo ra và suy nghĩ mọi thứ, nhưng việc thực hiện rất khó hiểu. Tôi nghĩ bây giờ tôi đã hiểu rõ hơn.
4 Sean Burton 27/07/2017
Đó là những quy tắc của TDD. Bạn được tự do viết mã tuy nhiên bạn muốn, nhưng nếu bạn không làm theo ba quy tắc bạn không làm TDD.
2 user3791372 27/07/2017
"Quy tắc" của một người? TDD là một gợi ý giúp bạn viết mã chứ không phải là một tôn giáo. Thật đáng buồn khi thấy rất nhiều người tuân theo ý tưởng đó một cách an toàn. Ngay cả nguồn gốc của TDD cũng gây tranh cãi.
2 Alex 28/07/2017
@ user3791372 TDD là một quy trình rất nghiêm ngặt và được xác định rõ ràng. Ngay cả khi nhiều người nghĩ rằng đó chỉ là có nghĩa là "Làm một số thử nghiệm khi bạn đang lập trình", nó không phải. Hãy cố gắng không trộn lẫn các điều khoản ở đây, câu hỏi này là về quá trình TDD, chứ không phải thử nghiệm chung.

Related questions

Hot questions

Language

Popular Tags