165
172

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

PHPUnitのテストコードを書くときによく使うイディオム

Last updated at Posted at 2017-05-02

0. 前提ライブラリ

1. 例外が発生することをテストする

PHPUnit 8系

/**
 * @test
 */
public function 例外が発生することをテストする()
{
    $this->expectException(ExceptionA::class);
    $classA = new ClassA();
    $classA->method1ClassA();
}

PHPUnit 7系以下

/**
 * @test
 * @expectedException ExceptionA
 */
public function 例外が発生することをテストする()
{
    $classA = new ClassA();
    $classA->method1ClassA();
}

2. 例外が発生しないことをテストする

/**
 * @test
 */
public function 例外が発生しないことをテストする()
{
    $classA = new ClassA();
    try {
        $classA->method1ClassA();
    } catch (ExceptionA $e) {
        $this->fail();
    }
    $this->assertTrue(true);
}

3. publicメソッドのモックを作ってテストする

/**
 * @test
 */
public function publicメソッドのモックを作ってテストする()
{
   $mockClassB = Mockery::mock('ClassB');
   $mockClassB->shouldReceive('method1ClassB')->andReturn('some value');
   $classA = new ClassA($mockClassB);
   $classA->method1ClassA();
}

4. publicプロパティのモックを作ってテストする

/**
 * @test
 */
public function publicプロパティのモックを作ってテストする()
{
    $mockClassB = Mockery::mock('ClassB');
    $mockClassB->property1ClassB = 'some value';
    $classA = new ClassA($mockClassB);
    $classA->method1ClassA();
}

5. public staticメソッドのモックを作ってテストする

/**
 * @test
 * @runInSeparateProcess
 * @preserveGlobalState disabled
 */
public function public_staticメソッドのモックを作ってテストする()
{
    $mockClassB = Mockery::mock('alias:ClassB');
    $mockClassB->shouldReceive('method1ClassB')->andReturn('some value');
    $classA = new ClassA();
    $classA->method1ClassA();
}

6. publicメソッドのモックを作ってテストする(クラス名がハードコーディングされている場合)

/**
 * @test
 * @runInSeparateProcess
 * @preserveGlobalState disabled
 */
public function publicメソッドのモックを作ってテストするクラス名がハードコーディングされている場合()
{
    $mockClassB = Mockery::mock('overload:ClassB');
    $mockClassB->shouldReceive('method1ClassB')->andReturn('some value');
    $classA = new ClassA();
    $classA->method1ClassA();
}

7. 自クラスのpublicメソッドのモックを作ってテストする

/**
 * @test
 */
public function 自クラスのpublicメソッドのモックを作ってテストする()
{
    $partialMockClassA = Mockery::mock('ClassA')->makePartial();
    $partialMockClassA->shouldReceive('method2ClassA')->andReturn('some value');
    $partialMockClassA->method1ClassA();
}

例7-1. 依存クラスのコンストラクタ呼び出しをモックしてテストする

class ClassA
{
    public function method1ClassA()
    {
        $classB = $this->newClassB();
    }

    /**
     * コンストラクタのモックは作れないのでインスタンス生成処理をラップする
     */
    public function newClassB()
    {
        return new ClassB();
    }
}
/**
 * @test
 */
public function 依存クラスのコンストラクタ呼び出しをモックしてテストする()
{
    $mockClassB = Mockery::mock('ClassB');
    $partialMockClassA = Mockery::mock('ClassA')->makePartial();
    $partialMockClassA->shouldReceive('newClassB')->andReturn($mockClassB);
    $partialMockClassA->method1ClassA();
}

8. チェインしたpublicメソッドのモックを作ってテストする

/**
 * @test
 */
public function チェインしたpublicメソッドのモックを作ってテストする()
{
    $mockClassB = Mockery::mock('ClassB');
    $mockClassB->shouldReceive('method1ClassB->method2ClassB')->andReturn('some value');
    $classA = new ClassA($mockClassB);
    $classA->method1ClassA();
}

9. [Laravel] ファサードのpublicメソッドのモックを作ってテストする

/**
 * @test
 */
public function ファサードのpublicメソッドのモックを作ってテストする()
{
    FacadeA::shouldReceive('method1FacadeA')->andReturn('some value');
    $classA = new ClassA();
    $classA->method1ClassA();
}

10. [Laravel] Eloquentのpublicメソッドのモックを作ってテストする

/**
 * @test
 */
public function Eloquentのpublicメソッドのモックを作ってテストする()
{
    $mockEloquentA = Mockery::mock('EloquentA');
    $mockEloquentA->shouldReceive('method1EloquentA')->andReturn('some value');
    $classA = new ClassA($mockEloquentA);
    $classA->method1ClassA();
}

11. [Laravel] Eloquentのpublicプロパティのモックを作ってテストする

/**
 * @test
 */
public function Eloquentのpublicプロパティのモックを作ってテストする()
{
    $mockEloquentA = Mockery::mock('EloquentA')->makePartial();
    $mockEloquentA->property1EloquentA = 'some value';
    $classA = new ClassA($mockEloquentA);
    $classA->method1ClassA();
}

12. private/protectedメソッドをテストする

/**
 * @test
 */
public function privateメソッドをテストする()
{
    $classA = new ClassA();
    $reflectionMethod1ClassA = new ReflectionMethod($classA, 'method1ClassA');
    $reflectionMethod1ClassA->setAccessible(true);
    $reflectionMethod1ClassA->invoke($classA);
}

13. private/protectedプロパティの値を書き換えてテストする

/**
 * @test
 */
public function privateプロパティの値を書き換えてテストする()
{
    $classA = new ClassA();
    $reflectionClassA = new ReflectionClass($classA);
    $reflectionProperty1ClassA = $reflectionClassA->getProperty('property1ClassA');
    $reflectionProperty1ClassA->setAccessible(true);
    $reflectionProperty1ClassA->setValue($classA, 'some value');
    $classA->method1ClassA();
}

14. private/protectedプロパティの値をテストする

/**
 * @test
 */
public function privateプロパティの値をテストする()
{
    $classA = new ClassA();
    $classA->method1ClassA();
    $reflectionClassA = new ReflectionClass($classA);
    $reflectionProperty1ClassA = $reflectionClassA->getProperty('property1ClassA');
    $reflectionProperty1ClassA->setAccessible(true);
    $valueReflectionProperty1ClassA = $reflectionProperty1ClassA->getValue($classA);
    $this->assertEquals('some value', $valueReflectionProperty1ClassA);
}

15. 仮想ファイルを使ってファイルの読み書きをテストする

/**
 * @test
 */
public function 仮想ファイルを使ってファイルの読み書きをテストする()
{
    $root = vfsStream::setup('root');                                          
    vfsStream::newFile('file')->at($root)->setContent('some contents');                                                                                                          
    $path = vfsStream::url('root/file');                                       
    $classA = new ClassA($path);                                                    
    $classA->method1ClassA();  
}

16. 無名クラスを使ってトレイトをテストする

/**
 * @test
 */
public function 無名クラスを使ってトレイトをテストする()
{
    $classUsingTrait = new class($property) {
        use TraitA;

        public function __construct($property)
        {
             $this->method1TraitA($property);
        }
    };
    $classUsingTrait->method2TraitA();
}

17. 未実装のテストをスキップする

/**
 * @test
 */
public function 未実装のテストをスキップする()
{
    $this->markTestIncomplete('このテストはまだ実装されていません。'); 
}

18. アサーションがないテストをリスキーと見なさない

PHPUnit 9系

/**
 * @test
 */
public function アサーションがないテストをリスキーと見なさない()
{
    $this->expectNotToPerformAssertions();
    new ClassA();
}

PHPUnit 8系以下

/**
 * @test
 * @doesNotPerformAssertions
 */
public function アサーションがないテストをリスキーと見なさない()
{
    new ClassA();
}
165
172
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
165
172

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?