phpunit tránh đối số hàm tạo cho mô hình


85

Cách để tránh phpunit phải gọi hàm tạo cho một đối tượng giả là gì? Nếu không, tôi sẽ cần một đối tượng giả làm đối số phương thức khởi tạo, một đối tượng khác cho đối tượng đó, v.v. Api có vẻ như thế này:

getMock($className, $methods = array(), array $arguments = array(),
        $mockClassName = '', $callOriginalConstructor = TRUE,
        $callOriginalClone = TRUE, $callAutoload = TRUE)

Tôi không làm cho nó hoạt động. Nó vẫn phàn nàn về đối số của hàm tạo, ngay cả khi $callOriginalConstructorđặt thành false.

Tôi chỉ có một đối tượng trong hàm tạo và nó là một phần phụ thuộc. Vì vậy, tôi không nghĩ rằng tôi có một vấn đề thiết kế ở đó.

Câu trả lời:


139

Bạn có thể sử dụng getMockBuilderthay vì chỉ getMock:

$mock = $this->getMockBuilder('class_name')
    ->disableOriginalConstructor()
    ->getMock();

Xem phần "Bộ đôi kiểm tra" trong tài liệu của PHPUnit để biết chi tiết.

Mặc dù bạn có thể làm điều này, nhưng tốt hơn là không cần phải làm. Bạn có thể cấu trúc lại mã của mình để thay vì một lớp cụ thể (với một hàm tạo) cần được đưa vào, bạn chỉ phụ thuộc vào một giao diện. Điều này có nghĩa là bạn có thể giả lập hoặc khai thác giao diện mà không cần phải yêu cầu PHPUnit sửa đổi hành vi của hàm tạo.


Điều này làm việc tuyệt vời cho tôi. Tuy nhiên, nó phải là ví dụ 10.3. Tôi đã cố gắng chỉnh sửa bài đăng nhưng SO đã loại bỏ nó vì bản chỉnh sửa quá ngắn.
Ma-thi-ơ

Cảm ơn @Lytithwyn. Đã cập nhật câu trả lời.
dave1010

42

Của bạn đây:

    // Get a Mock Soap Client object to work with.
    $classToMock = 'SoapClient';
    $methodsToMock = array('__getFunctions');
    $mockConstructorParams = array('fake wsdl url', array());
    $mockClassName = 'MyMockSoapClient';
    $callMockConstructor = false;
    $mockSoapClient = $this->getMock($classToMock,
                                     $methodsToMock,
                                     $mockConstructorParams,
                                     $mockClassName,
                                     $callMockConstructor);

Đây dường như là điều tôi muốn. Tôi muốn gọi getMock chỉ có lớp được chế tạo và $ callMockConstructor. Làm sao? một cái gì đó giống như sau: $ this-> getMock ($ classToMock, $ callMockConstructor). Điều duy nhất tôi có thể nghĩ đến là vào nguồn của PHPUnit và thay đổi nó thành default = false.
Gutzofter

1
Tôi đã thay đổi mặc định thành false trong testcase.php. Bạn sẽ nghĩ rằng nó sẽ được đặt thành false theo mặc định.
Chế giễu

Câu trả lời xuất sắc. Đúng là những gì tôi đang tìm kiếm
Hades

4

Như một phụ lục, tôi muốn đính kèm expects()các lệnh gọi vào đối tượng bị chế nhạo của mình và sau đó gọi hàm tạo. Trong PHPUnit 3.7.14, đối tượng được trả về khi bạn gọi disableOriginalConstructor()thực sự là một đối tượng.

// Use a trick to create a new object of a class
// without invoking its constructor.
$object = unserialize(
sprintf('O:%d:"%s":0:{}', strlen($className), $className)

Thật không may, trong PHP 5.4 có một tùy chọn mới mà họ không sử dụng:

ReflectionClass :: newInstanceWithoutConstructor

Vì điều này không có sẵn, tôi phải phản ánh lớp theo cách thủ công và sau đó gọi hàm tạo.

$mock = $this->getMockBuilder('class_name')
    ->disableOriginalConstructor()
    ->getMock();

$mock->expect($this->once())
    ->method('functionCallFromConstructor')
    ->with($this->equalTo('someValue'));

$reflectedClass = new ReflectionClass('class_name');
$constructor = $reflectedClass->getConstructor();
$constructor->invoke($mock);

Lưu ý, nếu functionCallFromConstructprotected, bạn phải đặc biệt sử dụng setMethods()để phương thức được bảo vệ bị chế nhạo. Thí dụ:

    $mock->setMethods(array('functionCallFromConstructor'));

setMethods()phải được gọi trước expect()cuộc gọi. Cá nhân, tôi xâu chuỗi điều này sau disableOriginalConstructor()nhưng trước đây getMock().


Không biết đây có phải là mùi mã hay không, nhưng điều này rất hiệu quả đối với tôi và tôi chỉ muốn cảm ơn bạn.
devbanana

1

Có lẽ bạn cần tạo một sơ khai để chuyển vào làm đối số của hàm tạo. Sau đó, bạn có thể phá vỡ chuỗi các đối tượng giả đó.


1

Ngoài ra, bạn có thể thêm một tham số vào getMock để ngăn việc gọi hàm tạo mặc định.

$mock = $this->getMock(class_name, methods = array(), args = array(), 
        mockClassName = '', callOriginalConstructor = FALSE);

Tuy nhiên, tôi nghĩ rằng câu trả lời của dave1010 trông đẹp hơn, điều này chỉ nhằm mục đích hoàn thiện.


1

Câu hỏi này hơi cũ, nhưng đối với những người mới truy cập, bạn có thể thực hiện nó bằng cách sử dụng createMockphương pháp (đã được gọi createTestDoublevà giới thiệu trước đó trong v5.4.0).

$mock = $this->createMock($className);

Như bạn có thể thấy trong đoạn mã dưới đây được trích xuất từ PHPUnit\Framework\TestCaselớp (in phpunit/src/framework/TestCase.php), về cơ bản nó sẽ tạo một đối tượng giả mà không cần gọi hàm tạo ban đầu .

/** PHPUnit\Framework\TestCase::createMock method */
protected function createMock(string $originalClassName): MockObject
{
    return $this->getMockBuilder($originalClassName)
                ->disableOriginalConstructor()
                ->disableOriginalClone()
                ->disableArgumentCloning()
                ->disallowMockingUnknownTypes()
                ->getMock();
}

0

PHPUnit được thiết kế để gọi phương thức khởi tạo trên các đối tượng giả mạo; để ngăn chặn điều này, bạn nên:

  1. Chèn một đối tượng giả làm phụ thuộc vào đối tượng bạn đang gặp khó khăn khi chế tạo
  2. Tạo một lớp thử nghiệm mở rộng lớp bạn đang cố gọi mà không gọi hàm tạo cha
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.