summaryrefslogtreecommitdiff
path: root/demos/time-tracker/protected/pages/Docs/MoreTests.page
blob: 5e598982d5298b8cc15e01fc0c48e1504d990555 (plain)
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
<com:TContent ID="body">

<h1>Finishing up test case</h1>
<p>Up to this point, you should have the follow pieces of files and code.
<img src=<%~ project1.png %> class="figure" />
</p>

<p>So what else can we test for at this point? A few reasonable
tests are to see what happens if the project already exists, and what if
the username does not exists.</p>

<p>First we shall refactor our test code since much of the setup code 
for the mocked connection will need to be repeated in other test assertions.
We change the test case to have these three new methods.
</p>

<com:TTextHighlighter Language="php" CssClass="source">
function setupMockConnectionFor($project)
{
	$customer = new TimeTrackerUser();
	$customer->ID = 1;
	$customer->Name = "Customer A";
	
	$manager = new TimeTrackerUser();
	$manager->ID = 2;
	$manager->Name = "Manager A";
	
	$conn = $this->connection;
	
	//return the customer and manager
	$conn->setReturnValue('queryForObject', 
				$customer, array('GetUserByName', 'Customer A'));
	$conn->setReturnValue('queryForObject', 
				$manager, array('GetUserByName', 'Manager A'));
	
	//project does not exist
	$conn->setReturnValue('queryForObject', 
				null, array('GetProjectByName', 'Project 1'));
	
	$param['project'] = $project;
	$param['creator'] = $customer->ID;
	$param['manager'] = $manager->ID; 
			
	$conn->setReturnValue('insert', 
				true, array('CreateNewProject', $param));
	$conn->setReturnReference('queryForObject', 
				$project, array('GetProjectByID', 1));	
}

function createNewTestProject()
{
	$project = new Project();
	$project->Name = "Project 1";
	$project->CreatorUserName = "Customer A";
	$project->ManagerUserName = "Manager A";
	
	return $project;
}

function assertProjectCreated($project)
{
	$this->assertTrue($this->dao->createNewProject($project));		
	$this->assertEqual($this->dao->getProjectByID(1), $project);
}
</com:TTextHighlighter>

<p>Our refactored test method <tt>testProjectDaoCanCreateNewProject()</tt> 
is as follows.</p>
<com:TTextHighlighter Language="php" CssClass="source">
function testProjectDaoCanCreateNewProject()
{
	$project = $this->createNewTestProject();

	if(($conn = $this->connection) instanceof MockTSqlMapper)
	{
		$this->setupMockConnectionFor($project);
		$conn->expectMinimumCallCount('queryForObject', 3);
		$conn->expectAtLeastOnce('insert');
	}
	
	$this->assertProjectCreated($project);	
}
</com:TTextHighlighter>

<p>To test that the project already exists, we modify the mock
connection and test for an exception.</p>
<com:TTextHighlighter Language="php" CssClass="source">
function testProjectExistsException()
{
	$project = $this->createNewTestProject();
	
	if(($conn = $this->connection) instanceof MockTSqlMapper)
	{
		//make the project exist
		$conn->setReturnValue('queryForObject', 
				$project, array('GetProjectByName', 'Project 1'));
		$this->setupMockConnectionFor($project);
	}
	
	try
	{
		$this->assertProjectCreated($project);		
		$this->fail();
	}
	catch(TimeTrackerException $e)
	{
		$this->pass();
	}
}
</com:TTextHighlighter>

<p>Other test method for testing missing customer and manager users
are done similarly. At this point, the test case file looks quite large.
We shall not add more tests to this case and we should rename the file 
from <tt>ProjectDaoTestCase.php</tt> to <tt>CreateNewProjectTestCase.php</tt>.

<div class="note"><b class="tip">Note:</b>
A heirachical exception class may be more useful in testing for specific
exceptions. For simplicity, we decided to use only <tt>TimeTrackerException</tt>
for this small project.
</div>

<div class="tip"><b class="tip">Tip:</b>Class, method and file naming is very
important to any project, the name should inform you at first glance what
is to be expected from the class, method or file. In addition, the naming
scheme should be uniform over the project.
</div>

<div class="info"><b class="tip">Comment:</b>
These test may be too ridget as any changes to the implementation may
actually cause the tests to fail. This is the case with grey-box/white-box
testing, you are actually testing the implementation. Black box tests may
be more preferable, as it should only test the class interface (the method or 
function details such as parameters and may be return values). However, 
with the use of database connection to retrive data within the objects under test,
it may be more suitable to do intergration tests.
</div>

</com:TContent>