﻿1
00:00:00,520 --> 00:00:04,840
Hello, in this sequence we'll look
at the SUnit test framework in Pharo,

2
00:00:05,000 --> 00:00:08,720
which allow us to write unit tests,
as you're going to see.

3
00:00:08,880 --> 00:00:13,200
A test framework is used
to support Agile development.

4
00:00:13,360 --> 00:00:16,560
The idea is to do incremental
development and to test

5
00:00:16,720 --> 00:00:18,720
your code regularly to check

6
00:00:18,880 --> 00:00:23,240
that in modifying it we haven't broken
a property or invariant in the code.

7
00:00:23,400 --> 00:00:25,240
We want to be prepared for changes.

8
00:00:25,400 --> 00:00:28,160
We write tests then we modify our codes

9
00:00:28,320 --> 00:00:30,520
then we can re-execute the tests

10
00:00:30,680 --> 00:00:33,680
to check we haven't broken or modified
anything we shouldn't have.

11
00:00:33,880 --> 00:00:38,520
Automated tests are very important
in supporting this kind of programming.

12
00:00:38,680 --> 00:00:42,680
The SUnit framework is
a special framework for writing tests.

13
00:00:42,840 --> 00:00:46,400
It makes them easier to write.
It's in 4 classes, it's very simple.

14
00:00:46,560 --> 00:00:48,960
It was originally
developed by Kent Beck,

15
00:00:49,120 --> 00:00:52,960
and has inspired numerous tests
in other languages,

16
00:00:53,120 --> 00:00:55,040
like JUnit, for example.

17
00:00:55,840 --> 00:00:57,440
So, what is a test?

18
00:00:57,600 --> 00:01:00,080
There are 3 steps to writing a test:

19
00:01:00,240 --> 00:01:04,960
Step one, we create a context,
for example, an empty set.

20
00:01:05,120 --> 00:01:07,480
Step two, I create a stimulus,

21
00:01:07,640 --> 00:01:11,960
here, so I try to insert
an element twice

22
00:01:12,120 --> 00:01:14,840
in the set I've just created,

23
00:01:15,000 --> 00:01:18,760
and step three,
I test the result that I get,

24
00:01:18,920 --> 00:01:23,160
which means that I wait until
the set only contains one element.

25
00:01:23,320 --> 00:01:26,960
A set object can only contain
an element once.

26
00:01:27,120 --> 00:01:28,680
It can't contain it twice.

27
00:01:28,840 --> 00:01:32,520
Then I test the result,
hoping the variant isn't broken.

28
00:01:33,120 --> 00:01:35,320
Here's an example.
To write a test...

29
00:01:35,480 --> 00:01:40,760
I have to write a TestCase subclass.
I'll call this one "SetTestCase".

30
00:01:40,920 --> 00:01:44,480
It's to test the sets.
I define the method, "testAdd".

31
00:01:44,640 --> 00:01:47,240
All the methods begin with "test".

32
00:01:47,400 --> 00:01:48,960
Then I set up the context,

33
00:01:49,120 --> 00:01:52,200
I create an instance
of the Set class, which is empty,

34
00:01:52,360 --> 00:01:55,840
I add 2 elements,
the same element twice...

35
00:01:56,000 --> 00:01:59,240
I try and add the same element twice

36
00:01:59,400 --> 00:02:03,360
to the bundle,
so 5 twice, here and here.

37
00:02:03,520 --> 00:02:06,000
Then I test it, I've "check" here,

38
00:02:06,160 --> 00:02:08,600
I use "assert" to do this,

39
00:02:09,920 --> 00:02:12,840
where I check that the size of my set

40
00:02:13,000 --> 00:02:16,480
is 1, that I've succeeded
in only adding the element once.

41
00:02:16,640 --> 00:02:19,320
I can start the test thanks to this...

42
00:02:20,720 --> 00:02:24,280
Thanks to this expression,
so my test will reveal

43
00:02:24,440 --> 00:02:28,760
if the variance, if "assert",
the expression passed here, is true.

44
00:02:29,560 --> 00:02:30,880
All the methods that begin

45
00:02:31,080 --> 00:02:34,960
with the string "test" represent a test,

46
00:02:35,120 --> 00:02:39,640
and will be automatically executed
by the test runner tool.

47
00:02:40,440 --> 00:02:44,480
We'll see that all the results,
all the executions of the test method

48
00:02:44,640 --> 00:02:48,040
produce a result.
All these results are collected,

49
00:02:48,200 --> 00:02:52,560
and they're collected within
a class instance object, TestResult.

50
00:02:54,120 --> 00:02:55,760
I'll give you another example.

51
00:02:55,920 --> 00:02:59,920
In this example, we've the test method,
its name begins with "test"

52
00:03:00,080 --> 00:03:03,560
in lowercase, and this
is the name of this method,

53
00:03:03,720 --> 00:03:07,240
"AdjacentRunsWithEquals
AttributesAreMerged"

54
00:03:07,400 --> 00:03:12,960
So we've the context here,
we've created an object.

55
00:03:13,120 --> 00:03:14,720
Here we've a stimulus.

56
00:03:14,880 --> 00:03:18,640
We've tried to send the message
"addLast times"

57
00:03:18,800 --> 00:03:22,760
to this object 3 times,
the 1st time with

58
00:03:22,920 --> 00:03:26,880
the settings here,
and a 2nd time, the same settings

59
00:03:27,040 --> 00:03:28,640
the 2nd and 3rd time.

60
00:03:28,800 --> 00:03:31,560
We test here, it's the check,

61
00:03:31,720 --> 00:03:35,760
that this element is size 2.
All right?

62
00:03:35,960 --> 00:03:40,960
We weren't able to add the same
element several times adjacently.

63
00:03:41,720 --> 00:03:46,320
In the execution of a test,
several scenarios can occur.

64
00:03:46,640 --> 00:03:50,720
One scenario is what we call
a "failure", meaning that

65
00:03:50,880 --> 00:03:53,720
one of the assertions,
a variant we thought was true,

66
00:03:53,880 --> 00:03:56,560
which should be true is false,
in which case

67
00:03:56,720 --> 00:04:01,560
the test which contains "failure"

68
00:04:01,720 --> 00:04:03,600
is an anticipated problem.

69
00:04:03,760 --> 00:04:09,240
We expected that, potentially,
this error would be present.

70
00:04:09,600 --> 00:04:13,160
After that, an error is a condition
we didn't check for.

71
00:04:13,320 --> 00:04:17,240
It's something that happens,
an exception that's raised,

72
00:04:17,400 --> 00:04:20,480
which we didn't expect
when writing the test.

73
00:04:20,640 --> 00:04:22,480
They're 2 very different cases.

74
00:04:23,120 --> 00:04:27,640
What do we do in a test
when we want to check

75
00:04:28,480 --> 00:04:32,000
that a bit of code
raises an exception?

76
00:04:32,160 --> 00:04:36,680
For example, I want to check
that "set new remove: 1"

77
00:04:36,840 --> 00:04:40,120
this bit of code,
will raise the exception "NotFound".

78
00:04:40,280 --> 00:04:42,520
If I do "Set new", it's an empty set.

79
00:04:42,680 --> 00:04:44,640
I'm trying to take an element
from an empty set.

80
00:04:44,800 --> 00:04:47,600
It doesn't make sense.
It will raise the exception "NotFound"

81
00:04:47,760 --> 00:04:50,800
and in my test I use "should raise".

82
00:04:50,960 --> 00:04:53,600
I pass a block
and in my evaluation of the block,

83
00:04:53,760 --> 00:04:55,240
if an exception is raised,

84
00:04:55,400 --> 00:04:59,440
and the exception is NotFound,
the test will be green, will be OK.

85
00:05:00,920 --> 00:05:02,280
I can also test the reverse,

86
00:05:02,440 --> 00:05:04,680
that a bit of code doesn't
raise an exception.

87
00:05:04,840 --> 00:05:08,440
Here I use the method
"self shouldn't raise".

88
00:05:08,600 --> 00:05:12,880
So this bit of code shouldn't
raise the exception "NotFound".

89
00:05:14,000 --> 00:05:16,960
We might, when writing lots of tests,

90
00:05:17,120 --> 00:05:19,480
realise that there are duplicates

91
00:05:19,640 --> 00:05:21,600
when writing the context of the test.

92
00:05:21,920 --> 00:05:23,880
For example,
here I've written another test

93
00:05:24,040 --> 00:05:26,120
for the sets, a "testOccurrences".

94
00:05:26,280 --> 00:05:31,800
We see that here, in the context,
I'm going to recreate a new empty set.

95
00:05:31,960 --> 00:05:35,120
Each time I write a test, I open a set,

96
00:05:35,280 --> 00:05:37,880
and each time I'll do
"Set new" in the context.

97
00:05:38,040 --> 00:05:41,920
We'd like not to repeat this line
every time in all of our tests.

98
00:05:42,080 --> 00:05:45,120
To not have to repeat them,
to be able to factor it out

99
00:05:45,280 --> 00:05:48,080
somewhere else, we have a solution.

100
00:05:48,240 --> 00:05:52,280
The SUnit solution
is to use the method "setUp"

101
00:05:52,440 --> 00:05:57,160
to factor out all the initializations
before execution of a test.

102
00:05:57,320 --> 00:05:59,680
So what actually happens is,

103
00:05:59,840 --> 00:06:02,280
at the moment a test is executed,
just before a test,

104
00:06:02,440 --> 00:06:05,560
therefore a method starting
with the test string, is executed,

105
00:06:05,720 --> 00:06:08,760
we'll trigger execution
of the method "setUp",

106
00:06:08,960 --> 00:06:11,200
and specify the context.

107
00:06:11,360 --> 00:06:15,320
During the test we'll use the stimuli

108
00:06:15,480 --> 00:06:17,280
and the check, the assertions,

109
00:06:17,440 --> 00:06:20,200
and at the end
of the execution of the test

110
00:06:20,360 --> 00:06:22,360
whether it fails or not,

111
00:06:22,520 --> 00:06:24,880
we'll execute the method "tearDown",

112
00:06:25,040 --> 00:06:26,960
which will allow us to clean up

113
00:06:27,120 --> 00:06:29,520
all the resources that
should be released.

114
00:06:29,680 --> 00:06:33,360
If we look at the execution
of several test methods, it's easy,

115
00:06:33,520 --> 00:06:35,400
we'll have the execution of "setUp"

116
00:06:35,560 --> 00:06:37,720
the first test method executed here,

117
00:06:37,880 --> 00:06:41,360
the execution of "tearDown" to clean,
a new execution of "setUp"

118
00:06:41,520 --> 00:06:44,720
the execution of a new test,
"tearDown", "setUp",

119
00:06:44,880 --> 00:06:47,760
the execution of a test
and "tearDown'.

120
00:06:47,920 --> 00:06:50,960
This allows us to factorize
implementation of the context,

121
00:06:51,120 --> 00:06:55,040
and clean up resources in two methods,
"setUp" and "tearDown".

122
00:06:56,240 --> 00:06:58,560
What does it look like?

123
00:06:58,720 --> 00:07:01,440
In our example,
if I take "SetTestCase"

124
00:07:01,600 --> 00:07:04,640
I can put in place
"define setUp method",

125
00:07:04,800 --> 00:07:07,320
in which I write,
"empty :=Set new",

126
00:07:07,480 --> 00:07:11,840
so "empty" becomes an instance
variable of "SetTestCase",

127
00:07:12,520 --> 00:07:14,560
and then in my test,
in my test method,

128
00:07:14,720 --> 00:07:18,080
I can directly use
the instance variable "empty",

129
00:07:18,240 --> 00:07:21,880
which was correctly initialized,
because before execution

130
00:07:22,040 --> 00:07:26,800
of "testOccurence"
the method "setUp" was executed.

131
00:07:29,680 --> 00:07:33,040
If we look at the organisation
of the classes

132
00:07:33,200 --> 00:07:37,600
within the core of SUnit,
as I said, there are only 4 classes:

133
00:07:37,760 --> 00:07:41,440
so one test case,
which is nothing more nor less

134
00:07:41,600 --> 00:07:43,560
than a test that verifies
that certain conditions,

135
00:07:43,720 --> 00:07:47,000
are true in a given context,
so one test case has

136
00:07:47,960 --> 00:07:50,280
one "setUp" method
one "tearDown" method

137
00:07:50,440 --> 00:07:52,840
and then a group of test methods.

138
00:07:53,000 --> 00:07:57,480
We write a "new" all the time,
the subclasses of the test case.

139
00:07:57,640 --> 00:08:00,520
These test cases are combined

140
00:08:00,680 --> 00:08:05,080
in a "TestSuite",

141
00:08:05,240 --> 00:08:08,560
and we can launch the execution
of a complete suite.

142
00:08:08,720 --> 00:08:11,640
When we launch the execution
of a suite we get a result,

143
00:08:11,800 --> 00:08:16,040
and this result is an instance
of "testResult" here,

144
00:08:16,200 --> 00:08:19,120
which tells us
how many tests have passed,

145
00:08:19,280 --> 00:08:22,800
how many tests have been executed,
how many have potentially

146
00:08:23,480 --> 00:08:26,240
met with failures and errors.

147
00:08:27,160 --> 00:08:29,560
We also have the notion
of "TestResource"

148
00:08:29,720 --> 00:08:33,960
which allows us to define
the TestResources for a whole suite.

149
00:08:36,040 --> 00:08:39,760
A TestCase, as I said,
represents one test.

150
00:08:39,920 --> 00:08:44,040
It's one method starting with "test"
defined in a subclass, TestCase.

151
00:08:45,360 --> 00:08:47,360
A TestSuite is a group of tests.

152
00:08:47,520 --> 00:08:52,320
It's all the TestCase methods
defined in one or several classes.

153
00:08:52,480 --> 00:08:56,880
And a TestResult will be a result
of several test executions.

154
00:08:58,160 --> 00:09:02,040
A TestResource
is an object that will enable

155
00:09:02,600 --> 00:09:05,120
the initialization
of a group of resources,

156
00:09:05,280 --> 00:09:07,520
which are costly
to initialize in normal time,

157
00:09:07,680 --> 00:09:10,280
and which we only want to
initialize once for a group of tests.

158
00:09:10,440 --> 00:09:14,400
We set up a TestResource, initialize
it once and execute lots of tests,

159
00:09:14,560 --> 00:09:17,440
and then we can release it at the end.

160
00:09:17,640 --> 00:09:20,320
What you should know

161
00:09:20,800 --> 00:09:24,520
is how to write tests.
Writing tests is extremely simple,

162
00:09:24,680 --> 00:09:27,480
you just have to write a subclass
of the TestCase class,

163
00:09:27,640 --> 00:09:31,240
define the methods in it
which begin with "test",

164
00:09:31,400 --> 00:09:33,440
and then set up a context inside it,

165
00:09:33,600 --> 00:09:36,960
send the stimuli and test
the assertions, which should be true.

166
00:09:37,800 --> 00:09:39,720
We'll reuse the contexts,

167
00:09:39,880 --> 00:09:42,240
so you can reuse the contexts
through several test methods,

168
00:09:42,400 --> 00:09:45,640
by factorizing them
in a SetUp method for example.

169
00:09:47,000 --> 00:09:52,080
To summarize, in this sequence
we've seen the SUnit test framework,

170
00:09:52,240 --> 00:09:54,360
which is extremely simple to use,

171
00:09:54,520 --> 00:09:57,560
and extremely efficient
for setting up Agile developments.

172
00:09:57,720 --> 00:10:01,520
I strongly urge you to use them,
defining tests is very easy.

173
00:10:01,680 --> 00:10:04,840
The big advantage is that when
you've created one test

174
00:10:05,000 --> 00:10:10,400
you can run it a million times
and it's really handy for making sure

175
00:10:10,560 --> 00:10:13,360
that your code still works,
even if you've changed things,

176
00:10:13,520 --> 00:10:16,640
and edge effects have occured,
you can detect them

177
00:10:16,800 --> 00:10:20,720
if you've been up-to-date
enough in the tests you've written.

178
00:10:20,880 --> 00:10:25,320
You can go further in creating tests
by using dot frameworks,

179
00:10:25,480 --> 00:10:28,640
typically Mock frameworks
like BabyMock, etc...

180
00:10:28,840 --> 00:10:33,440
to have different
styles of test and test writing.

181
00:10:34,480 --> 00:10:38,720
I encourage you to use and create
a lot of tests in your program.