Có thể giới thiệu các phương pháp chỉ được sử dụng trong các bài kiểm tra đơn vị không?


12

Gần đây tôi đã TDDing một phương pháp nhà máy. Phương pháp là tạo ra một vật thể đơn giản hoặc một vật thể được bọc trong một vật trang trí. Đối tượng được trang trí có thể là một trong một số loại tất cả mở rộng StrategClass.

Trong thử nghiệm của tôi, tôi muốn kiểm tra, nếu lớp của đối tượng được trả lại như mong đợi. Điều đó thật dễ dàng khi os đối tượng đơn giản trở lại, nhưng phải làm gì khi nó được bọc trong một vật trang trí?

Tôi viết mã bằng PHP để tôi có thể sử dụng ext/Reflectionđể tìm ra một lớp đối tượng được bao bọc, nhưng dường như tôi đang quá phức tạp mọi thứ và phần nào lại lặp lại các quy tắc của TDD.

Thay vào đó, tôi quyết định giới thiệu getClassName()rằng sẽ trả về tên lớp của đối tượng khi được gọi từ StrategClass. Tuy nhiên, khi được gọi từ trình trang trí, nó sẽ trả về giá trị được trả về bởi cùng một phương thức trong đối tượng được trang trí.

Một số mã để làm cho nó rõ ràng hơn:

interface StrategyInterface {
  public function getClassName();
}

abstract class StrategyClass implements StrategyInterface {
  public function getClassName() {
    return \get_class($this);
  }
}

abstract class StrategyDecorator implements StrategyInterface {

  private $decorated;

  public function __construct(StrategyClass $decorated) {
    $this->decorated = $decorated;
  }

  public function getClassName() {
    return $this->decorated->getClassName();
  }

}

Và một bài kiểm tra PHPUnit

 /**
   * @dataProvider providerForTestGetStrategy
   * @param array $arguments
   * @param string $expected
   */
  public function testGetStrategy($arguments, $expected) {

    $this->assertEquals(
      __NAMESPACE__.'\\'.$expected,  
      $this->object->getStrategy($arguments)->getClassName()
    )
  }

//below there's another test to check if proper decorator is being used

Quan điểm của tôi ở đây là: có ổn không khi giới thiệu các phương pháp như vậy, không có cách sử dụng nào khác ngoài việc làm cho các bài kiểm tra đơn vị dễ dàng hơn? Bằng cách nào đó nó không cảm thấy đúng với tôi.


Có lẽ câu hỏi này sẽ ném cái nhìn sâu sắc hơn về câu hỏi của bạn, programmers.stackexchange.com/questions/231237/... , tôi tin rằng nó phụ thuộc vào việc sử dụng và liệu những phương pháp rất nhiều sẽ hỗ trợ trong việc kiểm tra đơn vị và gỡ lỗi của bất cứ ứng dụng mà bạn đang phát triển .. .
Clement Mark-Aaba

Câu trả lời:


13

Tôi nghĩ là không, bạn không nên làm bất cứ điều gì chỉ vì nó cần thiết cho khả năng kiểm tra. Rất nhiều quyết định mà mọi người đưa ra có lợi cho khả năng kiểm tra và khả năng kiểm tra thậm chí có thể là lợi ích chính nhưng nó phải là một quyết định thiết kế tốt cho các công đức khác. Điều này không có nghĩa là một số thuộc tính mong muốn không thể kiểm tra được. Một ví dụ khác là khi bạn cần biết một số thói quen hiệu quả như thế nào, ví dụ Hashmap của bạn sử dụng một phạm vi giá trị băm phân bố đồng đều - không có gì trong giao diện bên ngoài có thể cho bạn biết điều đó.

Thay vì suy nghĩ, "tôi có nhận được lớp chiến lược phù hợp không" nghĩ "liệu lớp tôi nhận được có thực hiện những gì mà thông số này đang cố gắng kiểm tra không?" Thật tuyệt khi bạn có thể kiểm tra hệ thống ống nước bên trong nhưng bạn không phải làm thế, chỉ cần thử xoay núm và xem bạn có bị nước nóng hay lạnh không.


+1 OP đang mô tả thử nghiệm đơn vị 'hộp rõ ràng', không phải thử nghiệm tính năng TDD
Steven A. Lowe

1
Tôi thấy điều này, mặc dù tôi hơi miễn cưỡng khi thêm thử nghiệm thuật toán StrategClass khi tôi muốn kiểm tra xem phương thức nhà máy có thực hiện công việc đó không. Đây là loại phá vỡ cô lập IMHO. Một lý do khác mà tôi muốn tránh đó là các lớp cụ thể này hoạt động trên cơ sở dữ liệu, vì vậy việc kiểm tra chúng đòi hỏi phải có thêm chế độ nhạo báng.
Mchl

Mặt khác và trong ánh sáng của câu hỏi này: programmers.stackexchange.com/questions/86656/... khi chúng ta phân biệt được "kiểm tra TDD" từ "kiểm tra đơn vị" này trở nên hoàn toàn tốt đẹp (vẫn còn cơ sở dữ liệu hệ thống ống nước mặc dù: P)
Mchl

Nếu bạn thêm các phương thức họ trở thành một phần của hợp đồng với người dùng của bạn. Bạn sẽ kết thúc với các lập trình viên gọi các hàm và nhánh chỉ kiểm tra của bạn dựa trên kết quả. Nói chung, tôi thích để lộ càng ít lớp càng tốt.
BillThor

5

Tôi đảm nhận điều này là - đôi khi bạn phải làm lại mã nguồn của mình một chút để làm cho nó dễ kiểm tra hơn. Điều đó không lý tưởng và không nên là một cái cớ để làm lộn xộn giao diện với các chức năng chỉ được sử dụng để thử nghiệm vì vậy kiểm duyệt thường là chìa khóa ở đây. Bạn cũng không muốn ở trong tình huống người dùng mã của bạn đột nhiên sử dụng các chức năng giao diện thử nghiệm để tương tác bình thường với đối tượng của bạn.

Cách ưa thích của tôi để xử lý việc này (và tôi phải xin lỗi rằng tôi không thể chỉ ra cách thực hiện điều này trong PHP vì tôi chủ yếu viết mã bằng các ngôn ngữ kiểu C) là cung cấp các hàm 'kiểm tra' theo cách mà chúng không tiếp xúc với thế giới bên ngoài bởi chính đối tượng, nhưng có thể được truy cập bởi các đối tượng dẫn xuất. Đối với mục đích thử nghiệm, sau đó tôi sẽ lấy ra một lớp sẽ xử lý sự tương tác với đối tượng mà tôi thực sự muốn kiểm tra và để thử nghiệm đơn vị sử dụng đối tượng cụ thể đó. Một ví dụ C ++ sẽ trông giống như thế này:

Loại sản xuất:

class ProdObj
{
  ...
  protected:
     virtual bool checkCertainState();
};

Kiểm tra lớp người trợ giúp:

class TestHelperProdObj : public ProdObj
{
  ...
  public:
     virtual bool checkCertainState() { return ProdObj::checkCertainState(); }
};

Theo cách đó, ít nhất bạn đang ở một vị trí mà bạn không phải phơi bày các hàm loại 'kiểm tra' trong đối tượng chính của mình.


Một cách tiếp cận thú vị. Tôi cần xem làm thế nào tôi có thể thích nghi với điều này
Mchl

3

Vài tháng trước, khi tôi đặt máy rửa chén mới mua của mình, rất nhiều nước chảy ra từ vòi, tôi nhận ra điều này có lẽ là do thực tế nó đã được thử nghiệm đúng cách trong nhà máy. Không có gì lạ khi thấy các lỗ lắp và các thứ trên máy móc đang ở đó - chỉ nhằm mục đích thử nghiệm trong dây chuyền lắp ráp.

Kiểm tra là quan trọng, nếu cần, chỉ cần thêm một cái gì đó cho nó.

Nhưng hãy thử một số lựa chọn thay thế. Tùy chọn dựa trên phản ánh của bạn không phải là tất cả xấu. Bạn có thể có một trình truy cập ảo được bảo vệ theo những gì bạn cần và tạo một lớp dẫn xuất để kiểm tra và khẳng định. Có lẽ bạn có thể chia lớp của bạn và kiểm tra một lớp lá kết quả trực tiếp. Ẩn phương thức kiểm tra với biến trình biên dịch trong mã nguồn của bạn cũng là một tùy chọn (Tôi hầu như không biết PHP, không chắc là có thể có trong PHP không).

Trong ngữ cảnh của bạn, bạn có thể quyết định không kiểm tra bố cục thích hợp trong trình trang trí, nhưng kiểm tra hành vi dự kiến ​​mà trang trí nên có. Điều này có lẽ sẽ tập trung phần nào vào hành vi hệ thống dự kiến ​​và không quá nhiều vào đặc tả kỹ thuật (mẫu trang trí mua gì cho bạn từ góc độ chức năng?).


1

Tôi là một người mới TDD tuyệt đối, nhưng dường như nó phụ thuộc vào phương pháp được thêm vào. Từ những gì tôi hiểu về TDD, các thử nghiệm của bạn có nghĩa vụ "thúc đẩy" việc tạo API của bạn ở một mức độ nào đó.

Khi nó ổn:

  • Miễn là phương thức không phá vỡ đóng gói và phục vụ mục đích phù hợp với trách nhiệm của đối tượng.

Khi nó không ổn:

  • Nếu phương thức này có vẻ như không bao giờ hữu ích, hoặc không có ý nghĩa liên quan đến các phương thức giao diện khác, thì nó có thể không phù hợp hoặc khó hiểu. Tại thời điểm đó, nó sẽ làm vẩn đục sự hiểu biết của tôi về đối tượng đó.
  • Ví dụ của Jeremy, "... khi bạn cần biết một số thói quen hiệu quả như thế nào, ví dụ Hashmap của bạn sử dụng một phạm vi giá trị băm phân bổ đều - không có gì trong giao diện bên ngoài có thể cho bạn biết điều đó."
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.