Generate many similar mock objects

You want to:

Create several instances of a particular mocked out class, all with the same mocked out methods.

Solution:

Supply a name for the mock class, and then use new as usual.

By default, PHPUnit creates mock objects with a name that includes, for all intents and purposes, a random string appended. However, if you pass an optional fourth argment to $this->getMock(), that string becomes the name of the mocked out class. You can then reference it just like any other class in your environment, including making new instances of it.

Note that while naively using multiple calls to $this->getMock() will technically work for small numbers of mocked classes, it doesn't scale as large as using a named mock class. Using a named mock class prevents PHPUnit from having to regenerate the same mock class multiple times, which will speed up your unit tests. Also, PHPUnit internally caches each generated mock class, so mocking large numbers of similar classes will chew through your memory. Finally, using a named mock class yields simpler and cleaner code, where you only need to change one place if you want to mock out an additional function.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<?php
 
require_once "PHPUnit/Framework.php";
 
class FilesMultiplier
{
    /*
     * Take in an array of file handles.
     * Read a pair of numbers from each file, mutiply, 
     * and write answer back to the file.
     */
    public function multiply($inputFiles)
    {
        foreach($inputFiles as $inputFile) {
            $line = $inputFile->read();
            $parts = explode(" ", $line);
            $a = (integer) $parts[0];
            $b = (integer) $parts[1];
            $result = ($a * $b);
            $inputFile->write($result);
        }
    }
}
 
class FileObject
{
    /*
     * This function reads a line from a file.
     */
    public function read()
    {
        // ... code omitted
    }
 
    /*
     * This function writes a value to a file
     */
    public function write($value)
    {
        // ... code omitted
    } 
}
 
class TestFilesMultiplier extends PHPUnit_Framework_TestCase
{
    public function test_multiply()
    {
        $multiplier = new FilesMultiplier();
 
        $inputFile = $this->getMock('FileObject',
                                    array('read',
                                          'write'),
                                    array(),
                                    'FileObject_test_multiply');
 
        $files = array();
        $inputFile->expects($this->once())
                  ->method('read')
                  ->will($this->returnValue("3 4"));
        $inputFile->expects($this->once())
                  ->method('write')
                  ->with("12");
        $files[] = $inputFile;
 
        $inputFile = new FileObject_test_multiply();
        $inputFile->expects($this->once())
                  ->method('read')
                  ->will($this->returnValue("36 19"));
        $inputFile->expects($this->once())
                  ->method('write')
                  ->with("684");
        $files[] = $inputFile;
 
        $result = $multiplier->multiply($files);
    }
}
 
?>