Làm thế nào để đi về kiểm tra mã không tiêm?


13

Vì vậy, tôi có đoạn mã sau đây được sử dụng trên toàn hệ thống của mình. Chúng tôi hiện đang viết các bài kiểm tra đơn vị hồi tưởng (muộn còn hơn không bao giờ là lý lẽ của tôi), nhưng tôi không thấy điều này sẽ kiểm tra được như thế nào?

public function validate($value, Constraint $constraint)
{
    $searchEntity = EmailAlertToSearchAdapter::adapt($value);

    $queryBuilder = SearcherFactory::getSearchDirector($searchEntity->getKeywords());
    $adapter = new SearchEntityToQueryAdapter($queryBuilder, $searchEntity);
    $query = $adapter->setupBuilder()->build();

    $totalCount = $this->advertType->count($query);

    if ($totalCount >= self::MAXIMUM_MATCHING_ADS) {
        $this->context->addViolation(
            $constraint->message
        );
    }
}

Về mặt khái niệm, điều này nên được áp dụng cho bất kỳ ngôn ngữ nào, nhưng tôi đang sử dụng PHP. Mã chỉ đơn giản là xây dựng một đối tượng truy vấn ElasticSearch, dựa trên một Searchđối tượng, lần lượt được xây dựng từ một EmailAlertđối tượng. Những cái này SearchEmailAlertchỉ là của POPO.

Vấn đề của tôi là tôi không thấy làm thế nào tôi có thể thử ra các SearcherFactory(trong đó sử dụng phương pháp tĩnh), cũng không phải SearchEntityToQueryAdapter, mà cần kết quả từ SearcherFactory::getSearchDirector các Searchví dụ. Làm cách nào để tôi tiêm thứ gì đó được tạo từ kết quả trong một phương thức? Có lẽ có một số mẫu thiết kế mà tôi không biết?

Cảm ơn vì bất kì sự giúp đỡ!


@DocBrown nó đang được sử dụng bên trong $this->context->addViolationcuộc gọi, bên trong if.
Bữa sáng iLike

1
Phải mù, xin lỗi.
Doc Brown

Vì vậy, tất cả các :: là thống kê?
Ewan

Vâng, trong PHP ::là dành cho các phương thức tĩnh.
Andy

@Ewan có, ::gọi một phương thức tĩnh trên lớp.
iLike Bữa sáng

Câu trả lời:


11

Có một số posibilite, làm thế nào để mô phỏng staticcác phương thức trong PHP, giải pháp tốt nhất tôi đã sử dụng là thư viện AspectMock , có thể được kéo qua trình soạn thảo (cách mô phỏng các phương thức tĩnh khá dễ hiểu từ tài liệu này).

Tuy nhiên, đó là cách khắc phục vào phút cuối cho một sự cố cần được khắc phục theo một cách khác.

Nếu bạn vẫn muốn kiểm tra đơn vị lớp chịu trách nhiệm chuyển đổi các truy vấn, có một cách khá nhanh để thực hiện.

Tôi giả sử ngay bây giờ validatephương thức này là một phần của một số lớp, cách khắc phục rất nhanh, không yêu cầu bạn chuyển đổi tất cả các lệnh gọi tĩnh thành cuộc gọi cá thể, là xây dựng các lớp đóng vai trò proxy cho các phương thức tĩnh của bạn và đưa các proxy này vào các lớp mà trước đây đã sử dụng các phương thức tĩnh.

class EmailAlertToSearchAdapterProxy
{
    public function adapt($value)
    {
        return EmailAlertToSearchAdapter::adapt($value);
    }
}

class SearcherFactoryProxy
{
    public function getSearchDirector(array $keywords)
    {
        return SearcherFactory::getSearchDirector($keywords);
    }
}

class ClassWithValidateMethod
{
    private $emailProxy;
    private $searcherProxy;

    public function __construct(
        EmailAlertToSearchAdapterProxy $emailProxy,
        SearcherFactoryProxy $searcherProxy
    )
    {
        $this->emailProxy = $emailProxy;
        $this->searcherProxy = $searcherProxy;
    }

    public function validate($value, Constraint $constraint)
    {
        $searchEntity = $this->emailProxy->adapt($value);

        $queryBuilder = $this->searcherProxy->getSearchDirector($searchEntity->getKeywords());
        $adapter = new SearchEntityToQueryAdapter($queryBuilder, $searchEntity);
        $query = $adapter->setupBuilder()->build();

        $totalCount = $this->advertType->count($query);

        if ($totalCount >= self::MAXIMUM_MATCHING_ADS) {
            $this->context->addViolation(
                $constraint->message
            );
        }
    }
}

Đây là hoàn hảo! Thậm chí không nghĩ đến proxy. Cảm ơn!
iLike Breakfast 20/05/2016

2
Tôi tin rằng Michael Feather đã gọi điều này là kỹ thuật "Bọc tĩnh" trong cuốn sách "Làm việc hiệu quả với Mã kế thừa".
RubberDuck

1
@RubberDuck Tôi không hoàn toàn chắc chắn rằng nó được gọi là proxy, phải trung thực. Đó là những gì tôi đã được gọi nó miễn là tôi có thể nhớ sử dụng nó, tên của ông Feather có lẽ phù hợp hơn, mặc dù tôi chưa đọc cuốn sách này.
Andy

1
Bản thân lớp chắc chắn là một "proxy". Kỹ thuật phá vỡ phụ thuộc được gọi là IIRC "bọc tĩnh". Tôi đánh giá cao cuốn sách. Nó chứa đầy đá quý như bạn đã cung cấp ở đây.
RubberDuck

5
Nếu công việc của bạn liên quan đến việc thêm các bài kiểm tra đơn vị vào mã, thì "làm việc với mã kế thừa" là một cuốn sách được đề xuất mạnh mẽ. Định nghĩa của ông về "mã kế thừa" là "mã không có kiểm tra đơn vị", toàn bộ cuốn sách trên thực tế là các chiến lược để thêm các thử nghiệm đơn vị vào mã chưa được kiểm tra hiện có.
Eterm

4

Đầu tiên, tôi khuyên bạn nên chia nó thành các phương thức riêng biệt:

public function validate($value, Constraint $constraint)
{
    $totalCount = QueryTotal($value);
    ShowMessageWhenTotalExceedsMaximum($totalCount,$constraint);
}

private function QueryTotal($value)
{
    $searchEntity = EmailAlertToSearchAdapter::adapt($value);

    $queryBuilder = SearcherFactory::getSearchDirector($searchEntity->getKeywords());
    $adapter = new SearchEntityToQueryAdapter($queryBuilder, $searchEntity);
    $query = $adapter->setupBuilder()->build();

    return $this->advertType->count($query);
}

private function ShowMessageWhenTotalExceedsMaximum($totalCount,$constraint)
{
    if ($totalCount >= self::MAXIMUM_MATCHING_ADS) {
        $this->context->addViolation(
            $constraint->message
        );
    }
}

Điều này khiến bạn rơi vào tình huống mà bạn có thể xem xét để thực hiện hai phương thức mới đó và thử nghiệm đơn vị QueryTotalShowMessageWhenTotalExceedsMaximumriêng lẻ. Một tùy chọn khả thi ở đây thực sự không phải là kiểm tra đơn vị QueryTotal, vì về cơ bản bạn sẽ chỉ kiểm tra tính năng Tìm kiếm đàn hồi. Viết một bài kiểm tra đơn vị ShowMessageWhenTotalExceedsMaximumsẽ dễ dàng và có ý nghĩa hơn nhiều, vì nó thực sự sẽ kiểm tra logic kinh doanh của bạn.

Tuy nhiên, nếu bạn muốn kiểm tra "xác thực" trực tiếp, hãy xem xét để chuyển chính hàm truy vấn dưới dạng tham số thành "xác thực" (với giá trị mặc định là $this->QueryTotal), điều này sẽ cho phép bạn giả định chức năng truy vấn. Tôi không chắc là mình có đúng cú pháp PHP hay không, vì vậy trong trường hợp tôi không biết, xin vui lòng đọc đây là "Mã giả":

public function validate($value, Constraint $constraint, $queryFunc=$this->QueryTotal)
{
    $totalCount =  $queryFunc($value);
    ShowMessageWhenTotalExceedsMaximum($totalCount,$constraint);
}

Tôi thích ý tưởng này, nhưng tôi muốn giữ mã theo hướng đối tượng hơn thay vì chuyển qua các phương thức như thế này.
Bữa sáng iLike

@iLike Breakfast thực sự phương pháp này là tốt bất kể điều gì khác. Một phương pháp nên càng ngắn càng tốt và làm tốt một việc và một điều (Chú Bob, Clean Code ). Điều này làm cho nó dễ đọc hơn, dễ hiểu hơn và dễ kiểm tra hơn.
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.