Làm cách nào tôi có thể bắt đầu sử dụng TDD để mã hóa một số chức năng đơn giản?


9

Tôi về cơ bản có ý chính của TDD. Tôi đã bán rằng nó hữu ích và tôi đã có một lệnh hợp lý của khung MSTEST. Tuy nhiên, cho đến nay tôi vẫn chưa thể tốt nghiệp để sử dụng nó như một phương pháp phát triển chính. Hầu hết, tôi sử dụng nó như một đại diện thay thế để viết các ứng dụng bảng điều khiển làm trình điều khiển thử nghiệm (phương pháp truyền thống của tôi).

Điều hữu ích nhất đối với tôi là cách nó hấp thụ vai trò của kiểm tra hồi quy.

Tôi chưa xây dựng bất cứ điều gì đặc biệt cô lập các hành vi có thể kiểm tra khác nhau, đó là một phần lớn của bức tranh mà tôi biết.

Vì vậy, câu hỏi này là để hỏi con trỏ về những thử nghiệm đầu tiên tôi có thể viết cho nhiệm vụ phát triển sau: Tôi muốn tạo mã bao gói thực thi nhiệm vụ theo cách thức của nhà sản xuất / người tiêu dùng.

Tôi đã dừng lại và quyết định viết câu hỏi này sau khi tôi viết mã này (tự hỏi liệu tôi có thực sự có thể sử dụng TDD lần này không)

Mã số:

interface ITask
{
    Guid TaskId { get; }
    bool IsComplete { get; }
    bool IsFailed { get; }
    bool IsRunning { get; }
}

interface ITaskContainer
{
    Guid AddTask(ICommand action);
}

interface ICommand
{
    string CommandName { get; }
    Dictionary<string, object> Parameters { get; }
    void Execute();
}

Bạn nên viết các bài kiểm tra trước và THEN các giao diện! Toàn bộ ý tưởng là TDD dành cho API của bạn.

1
Làm thế nào để một bài kiểm tra viết cho các giao diện chưa tồn tại? Họ thậm chí sẽ không biên dịch.
Robert Harvey

5
Đó là bài kiểm tra thất bại đầu tiên của bạn.
cori

Câu trả lời:


10

Bắt đầu với khái niệm này:
1) Bắt đầu với hành vi mà bạn mong muốn. Viết một bài kiểm tra cho nó. Xem thử nghiệm thất bại.
2) Viết đủ mã để vượt qua bài kiểm tra. Xem tất cả các bài kiểm tra vượt qua.
3) Tìm mã dự phòng / cẩu thả -> refactor. Xem xét nghiệm vẫn vượt qua. Đi 1

Vì vậy, trên # 1, giả sử bạn muốn tạo một lệnh mới (Tôi đang tìm hiểu cách thức hoạt động của lệnh, vì vậy hãy đồng ý với tôi). (Ngoài ra, tôi sẽ hơi thực dụng hơn là TDD cực đoan)

Lệnh mới được gọi là MakeMyLunch, vì vậy trước tiên bạn tạo một bài kiểm tra để khởi tạo nó và lấy tên lệnh:

@Test
public void instantiateMakeMyLunch() {
   ICommand command = new MakeMyLunchCommand();
   assertEquals("makeMyLunch",command.getCommandName());
}

Điều này không thành công, buộc bạn phải tạo lớp lệnh mới và để nó trả lại tên của nó (purist sẽ nói đây là hai vòng TDD, không phải 1). Vì vậy, bạn tạo lớp và yêu cầu nó thực hiện giao diện ICommand, bao gồm trả về tên lệnh. Chạy tất cả các bài kiểm tra hiện cho thấy tất cả vượt qua, vì vậy bạn tiến hành tìm kiếm cơ hội tái cấu trúc. Có lẽ là không.

Vì vậy, tiếp theo bạn muốn nó thực hiện thực thi. Vì vậy, bạn phải hỏi: làm thế nào để tôi biết rằng "MakeMyLunch" đã "ăn trưa" thành công. Những gì thay đổi trong hệ thống vì hoạt động này? Tôi có thể kiểm tra cái này không?

Giả sử nó dễ dàng để kiểm tra:

@Test
public void checkThatMakeMyLunchIsSuccessful() {
   ICommand command = new MakeMyLunchCommand();
   command.execute();
   assertTrue( Lunch.isReady() );
}

Những lần khác, điều này khó khăn hơn và điều bạn thực sự muốn làm là kiểm tra trách nhiệm của bài kiểm tra dưới chủ đề (MakeMyLunchCommand). Có lẽ trách nhiệm của MakeMyLunchCommand là tương tác với Tủ lạnh và Lò vi sóng. Vì vậy, để kiểm tra nó, bạn có thể sử dụng một Tủ lạnh giả và Lò vi sóng giả. [hai khung giả mẫu là MockitonMock hoặc xem tại đây .]

Trong trường hợp đó, bạn sẽ làm một cái gì đó giống như mã giả sau đây:

@Test
public void checkThatMakeMyLunchIsSuccessful() {
   Fridge mockFridge = mock(Fridge);
   Microwave mockMicrowave = mock(Microwave);
   ICommand command = new MakeMyLunchCommand( mockFridge, mockMicrowave );
   command.execute();
   mockFramework.assertCalled( mockFridge.removeFood );
   mockFramework.assertCalled( microwave.turnon );
}

Người theo chủ nghĩa thuần túy nói kiểm tra trách nhiệm của lớp bạn - tương tác của nó với các lớp khác (lệnh có mở tủ lạnh và bật lò vi sóng không?).

Người theo chủ nghĩa thực dụng nói kiểm tra cho một nhóm các lớp và kiểm tra kết quả (bữa trưa của bạn đã sẵn sàng chưa?).

Tìm sự cân bằng phù hợp với hệ thống của bạn.

(Lưu ý: xem xét rằng có lẽ bạn đã đến cấu trúc giao diện của mình quá sớm. Có lẽ bạn có thể để điều này phát triển khi bạn viết các bài kiểm tra và triển khai đơn vị của mình, và trong bước # 3, bạn "nhận thấy" cơ hội giao diện chung).


nếu tôi không viết trước giao diện của mình, câu hỏi nào sẽ dẫn đến việc tạo phương thức Execute () - một số nỗ lực ban đầu của tôi đối với TDD bị đình trệ khi tôi không có "bước" để kích thích chức năng bổ sung - tôi nhận được cảm giác có vấn đề về gà / trứng tiềm ẩn phải được bỏ qua
Aaron Anodide

1
Câu hỏi hay! Nếu lệnh duy nhất bạn thực hiện là "MakeMyLunchCommand" thì phương thức có thể đã bắt đầu bằng ".makeMyLunch ()". Mà sẽ ổn thôi. Sau đó, bạn thực hiện một lệnh khác ("NapCommand.takeNap ()"). Vẫn không có vấn đề với các phương pháp khác nhau. Sau đó, bạn bắt đầu sử dụng nó trong hệ sinh thái của mình, có khả năng là nơi bạn buộc phải khái quát hóa vào giao diện ICommand. Nói chung, bạn thường trì hoãn việc khái quát hóa cho đến thời điểm chịu trách nhiệm cuối cùng, bởi vì YAGNI [ en.wikipedia.org/wiki/You_ain't_gonna_need_it ] =) Những lần khác, bạn biết bạn sẽ đến đó nên bạn bắt đầu với nó.
jayraynet

(Ngoài ra các giả thiết ở đây là bạn đang sử dụng một IDE hiện đại mà làm cho refactoring những thứ như tên phương pháp tầm thường)
jayraynet

1
cảm ơn một lần nữa vì lời khuyên, đây là một cột mốc quan trọng để tôi cuối cùng cũng nhìn thấy tất cả các mảnh và cách chúng phù hợp - và vâng, bộ tái cấu trúc nhanh nằm trong hộp công cụ của tôi
Aaron Anodide
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.