2009-11-02 27 views
9

Khi tạo phương thức, mọi đối tượng được khởi tạo bên trong phương thức đó có được chuyển thành tham số sao cho các đối tượng đó có thể được mô phỏng trong các thử nghiệm đơn vị của chúng ta không?Đối tượng nào mô phỏng khi thực hiện TDD

Chúng tôi có rất nhiều phương pháp ở đây tại nơi làm việc không có kiểm tra đơn vị liên quan và khi viết thử nghiệm; chúng tôi thấy rằng có khá nhiều đối tượng được khởi tạo bên trong các phương thức này.

Một trong các tùy chọn của chúng tôi là cấu trúc lại các phương pháp hiện tại thành nhiều đơn vị hơn như phương pháp và giảm số lượng trách nhiệm cho mỗi phương pháp. Đây có thể là một quá trình dài nhưng chắc chắn là một lợi ích lớn cho chúng tôi trong tương lai.

Bạn nghĩ sao? Tất cả các đối tượng có được khởi tạo bên trong một phương thức có được truyền vào dưới dạng tham số không?

+0

"mọi đối tượng được khởi tạo bên trong phương thức đó được chuyển vào" Bạn có thể muốn viết lại điều này. Thật khó hiểu. Tôi nghĩ rằng bạn đang yêu cầu nếu "* thay vì * instantiating bên trong phương pháp họ nên được thông qua trong". Nó có ý nghĩa hơn một chút nếu chúng được coi là altenratives. –

Trả lời

7

Có thể không phải tất cả các đối tượng, nhưng càng có nhiều đối tượng bạn tiêm vào đơn vị của bạn, thì việc chia tách mối quan tâm của bạn càng trở nên tốt hơn, vì vậy tôi khuyên bạn nên di chuyển theo hướng đó.

Bạn không phải chuyển tất cả các đối tượng dưới dạng tham số phương thức. Nó thường là một thiết kế tốt hơn để tiêm cộng tác viên vào các lớp học thông qua Constructor Injection. Điều này giúp giao diện của bạn luôn sạch sẽ trong khi triển khai của bạn có thể nhập các cộng tác viên cần.

Hãy nói rằng việc thực hiện ban đầu của bạn trông như thế này:

public class Foo 
{ 
    public Ploeh DoStuff(Fnaah f) 
    { 
     var bar = new Bar(); 
     return bar.DoIt(f); 
    } 
} 

Điều này có thể được thay đổi để giống như thế này:

public class Foo 
{ 
    private readonly IBar bar; 

    public Foo(IBar bar) 
    { 
     this.bar = bar; 
    } 

    public Ploeh DoStuff(Fnaah f) 
    { 
     return this.bar.DoIt(f); 
    } 
} 

ý rằng tôi đã thay đổi bar từ một thể hiện của Bar để một thể hiện của IBar, do đó tách Foo khỏi việc triển khai cụ thể IBar. Việc tái cấu trúc như vậy có xu hướng làm cho các bài kiểm tra đơn vị của bạn đơn giản hơn để viết và duy trì, vì bây giờ bạn có thể thay đổi các triển khai của Foo và Bar một cách độc lập.

6

Phần đầu tiên là một câu hỏi được tải. Nó giống như yêu cầu "Khi chạy trên người đi bộ trong xe của tôi, tôi nên có cả hai tay trên bánh xe?"

Phương pháp khởi tạo nhiều đối tượng khác gần như chắc chắn đang làm quá nhiều. Một lớp học với nhiều phương pháp đó có lẽ không tuân theo nguyên tắc trách nhiệm duy nhất. Tuy nhiên, một trong những cách chính để làm cho mã của bạn có thể kiểm tra là sử dụng IoC (đảo ngược điều khiển), nơi phụ thuộc của lớp (hoặc phương thức) được chuyển cho nó, thay vì lớp yêu cầu chúng. Điều này làm cho nó dễ dàng hơn nhiều để kiểm tra, như bạn có thể vượt qua trong mocks.

Vì vậy, câu trả lời ngắn gọn là "Có", chuyển phụ thuộc của bạn và xem thành phần tốt dependency injection. Câu trả lời dài là "Có, nhưng đừng làm vậy". Các khung công tác DI có lẽ sẽ buộc bạn truyền các phụ thuộc vào các đối tượng thay vì các phương thức, và bạn sẽ thấy bạn muốn chắc chắn rằng bạn giới hạn những phụ thuộc đó - đó là một điều tốt.

Và chắc chắn, việc tái cấu trúc để giảm phụ thuộc là tốt. Rút ngắn các phương pháp của bạn để làm một điều hầu như không bao giờ là xấu. Tôi thực sự đồng ý rằng đây là một lợi ích lâu dài, miễn là bạn có thể chi trả các chi phí ngắn hạn.

+1

+1 cho tương tự. Đó là thứ hai và tôi cần một tiếng cười tốt. – wheaties

1

Tại một thời điểm nào đó bạn sẽ không thoát khỏi việc tạo ra từ một đối tượng này từ đối tượng khác nhưng bạn nên viết phần mềm theo nguyên tắc thiết kế tốt. Ví dụ. SRP, DI vv ..

Nơi bạn có nhiều phụ thuộc, bạn có thể tìm thấy một thùng chứa IoC sẽ giúp bạn quản lý tất cả.

Khi xử lý mã cũ, bạn có thể thấy hữu ích khi đọc số Working Effectively with Legacy code của Michael Feather. Cuốn sách có nhiều kỹ thuật về cách để hệ thống của bạn được kiểm tra.

0

Tôi không chắc chắn những gì ngôn ngữ/công cụ mà bạn đang sử dụng, nhưng cách nó có thể được thực hiện nó ray chỉ đơn giản là để chế nhạo các nhà xây dựng, như vậy:

@user = mock_model(User) 
User.stub(:create).and_return(@user) 

Vì vậy, từ bây giờ trở đi trong bạn nếu bạn gọi User.create (User là "Class"), nó sẽ luôn trả về biến @user được xác định trước của bạn, cho phép bạn kiểm soát toàn bộ dữ liệu nào đang được sử dụng trong các bài kiểm tra đơn vị của bạn. Bây giờ bạn biết chính xác dữ liệu nào trong các bài kiểm tra của mình, bạn có thể bắt đầu phân phát các phương thức thể hiện của các đối tượng để đảm bảo rằng chúng trả về dữ liệu thích hợp mà bạn có thể sử dụng để kiểm tra các phương thức của mình.

0

Bạn nên ưu tiên các phương pháp không có đối số, theo sau là một đối số, hai và cuối cùng là ba. Bất cứ điều gì lấy nhiều hơn 3 là một mùi mã. Hoặc là có một lớp đang chờ được khám phá trong tất cả các đối số đang được truyền vào hoặc lớp/phương pháp đang cố gắng làm quá nhiều.

Về mặt truyền tải phụ thuộc, bạn có thể sử dụng phép xây dựng nhưng theo thời gian, điều này trở nên khó sử dụng khi bạn từ từ di chuyển sang phải vượt qua toàn bộ biểu đồ đối tượng. Lời khuyên của tôi là chuyển sang sử dụng một container IoC sớm hơn là sau này và tránh được nỗi đau.

2

Chỉ cần quan sát: bạn đang nói về các phương pháp, trong khi tôi thích nói về các lớp học hơn.

Không có câu trả lời chung cho câu hỏi này. Đôi khi nó thực sự là quan trọng để decouple việc tạo ra một lớp học từ việc sử dụng.

xem xét:

  • nếu một lớp sử dụng khác, nhưng bạn muốn lỏng lẻo vài họ, bạn nên sử dụng một giao diện. Bây giờ, nếu chỉ có giao diện được biết, không phải là loại cụ thể, thì lớp đầu tiên sẽ tạo ra một cá thể như thế nào?
  • các lớp tách là rất quan trọng, nhưng không thể và không nên được thực hiện trong mọi trường hợp. Nếu nghi ngờ, nếu cần được tách rời.
  • Khi sử dụng tiêm, bạn cần quyết định người đang tạo và tiêm các phiên bản. Bạn sẽ hầu như có thể tìm thấy một khuôn khổ tiêm phụ thuộc như Spring.Net có ích.

Có một mẹo khác: thực hiện tiêm tùy chọn. Điều này có nghĩa, khi bạn vượt qua một thể hiện trong constructor, nó sẽ được sử dụng. Khi không, một cá thể mới được tạo ra bởi chính lớp đó. Điều này rất tiện lợi khi xử lý mã kế thừa và khi bạn không có khung tiêm phụ thuộc.

2

[Disclaimer: Tôi làm việc tại Typemock]
Bạn có ba tùy chọn - hai trong số đó đòi hỏi một số refactoring:

  1. đèo tất cả các đối số - như bạn đã biết cách này bạn có thể vượt qua mocks/khai thay vì các đối tượng "thực".
  2. Sử dụng thùng chứa IoC - cấu trúc lại mã của bạn để sử dụng vùng chứa để lấy các đối tượng từ mã của bạn và bạn có thể thay thế chúng bằng mocks/stubs.
  3. Sử dụng Typemock Isolator (.NET) có thể giả mạo các đối tượng trong tương lai - các đối tượng được khởi tạo bên trong mã của bạn từ mã kiểm tra. Tùy chọn này không yêu cầu tái cấu trúc và nếu bạn có một cơ sở mã lớn, nó sẽ đáng giá mã của nó.

Thiết kế để kiểm tra không phải lúc nào cũng là thực hành tốt, đặc biệt là với dự án hiện tại, nơi bạn đã viết một số mã. Vì vậy, nếu bạn đang bắt đầu làm sạch hoặc có một dự án nhỏ có lẽ nó là OK để vượt qua các đối tượng như là đối số cho constructor của lớp miễn là bạn không có quá nhiều tham số.
- Nếu bạn sử dụng vùng chứa IoC.

Nếu bạn không muốn thay đổi tất cả mã hiện có và/hoặc không muốn thiết kế mã theo một cách nhất định để làm cho nó "dễ kiểm tra hơn" (có thể gây ra một số mã tìm kiếm kỳ lạ hơn - sử dụng Isolator (hoặc tương tự) nếu bạn đang sử dụng Java)

2

Chỉ giả chế các đối tượng được cản trở khi viết các bài kiểm tra đơn vị.Nếu một phương pháp tạo một đối tượng để thực hiện nhiệm vụ của nó thì bạn có thể thăm dò kết quả của nó, sau đó không cần để giả lập lớp của đối tượng được tạo.

Sử dụng mô hình khi bạn muốn tách lớp khỏi lớp khác. Sử dụng mô hình để giữ cho các thử nghiệm cách xa

  • hệ thống tập tin
  • cơ sở dữ liệu
  • mạng
  • đối tượng với hành vi không thể đoán trước (đồng hồ, bộ tạo số ngẫu nhiên ...)

sử dụng riêng biệt của đối tượng từ xây dựng của họ

0

tôi sẽ cố gắng để sử dụng tiêm phụ thuộc vào lớp thay vì có phương thức lớp tạo đối tượng (như câu trả lời được chọn đề xuất). Khi điều đó không có ý nghĩa, hãy xem xét tạo một lớp nhà máy sản xuất các đối tượng đang được tạo ra. Sau đó bạn có thể vượt qua trong nhà máy đó thông qua tiêm phụ thuộc.

0

Tôi thích mô phỏng mọi thứ xung quanh một đối tượng và xác định hành vi của đối tượng đang được thử nghiệm về các cuộc gọi đến và phản hồi từ các đối tượng liên quan.

Để thực hiện điều này một cách hiệu quả, yêu cầu giao diện của bạn phải ở cấp ngữ nghĩa chứ không phải cấp thực hiện, nói chung.

Các vấn đề liên quan