Mock objects framework
# Mocketry
[](https://github.com/dionisiydk/Mocketry/releases/latest)
[](https://github.com/dionisiydk/Mocketry/actions/workflows/tests.yml)
[](https://pharo.org)
[](https://pharo.org)
[](https://pharo.org)
[](https://pharo.org)
[](https://pharo.org)
[](https://pharo.org)
[](https://pharo.org)
Mocketry is mock objects framework\. It provides simplest way to stub any message to any object and to verify any occurred behaviour
## Installation
The installation script (therefore version of StateSpecs) depends on Pharo version you are using it in.
Pharo 13 (master branch):
```Smalltalk
Metacello new
baseline: 'Mocketry';
repository: 'github://dionisiydk/Mocketry:master';
load
```
Pharo 6-12 (v7.0.2):
```Smalltalk
Metacello new
baseline: 'Mocketry';
repository: 'github://dionisiydk/Mocketry:v7.0.2';
load
```
Pharo <= 5:
```Smalltalk
Metacello new
smalltalkhubUser: 'dionisiy' project: 'Mocketry';
configuration: 'Mocketry';
version: #stable;
load.
```
To add dependency in your project baseline:
```Smalltalk
spec
baseline: 'Mocketry'
with: [ spec repository: 'github://dionisiydk/Mocketry:v7.0.2' ].
```
(replace the version in the URL depending on Pharo version as shown above with standalone scripts)
## Create mocks easily
To create mock just use **\#new**
```Smalltalk
yourMock := Mock new.
```
Mocketry not requires any special context variables for this\.
Also Mocketry implements auto naming logic to retrive variable names from test context\. Inside test yourMock will be shown as "a Mock\(yourMock\)" \(in debugger\)\.
But if you need special name you can specify it:
```Smalltalk
Mock named: 'yourMock'
```
You can look at it livelly in MockTests\.
Also there is way to get multiple mocks at once:
```Smalltalk
[ :mockA :mockB | "your code here" ] runWithMocks
```
## Stub any message sends
<a name="stubMessageSends"></a>To stub message send just send message **\#stub** to object and following message will create expectation:
```Smalltalk
mock := Mock new.
mock stub someMessage willReturn: 100.
mock someMessage should be: 100.
```
You can stub any objects\. It is not only about mocks:
```Smalltalk
rect := 0@0 corner: 2@3.
rect stub width willReturn: 1000.
rect area should be: 3000 "are = width * height"
```
And you can do this with globals too:
```Smalltalk
DateAndTime stub now willReturn: #constantValue.
DateAndTime now should be: #constantValue.
```
But you should be carefull with globals\. Don't try
```Smalltalk
Array stub new.
```
It will crash image\.
And if you stub global from workspace it is your responsibility to recover it from stub behaviour\. Do it by this:
```Smalltalk
DateAndTime recoverFromGHMutation.
```
In case when you stub global inside test Mocketry automatically recovers all global stubs when test completes\.
Also with Mocketry you can define expectations for set of objects\. For example you can stub message to **ANY object**:
```Smalltalk
Any stub width willReturn: 100.
mock := Mock new.
mock width should be: 100.
rect := 0@0 corner: 2@3.
rect stub. "#stub activates message intercection for real object. Without it following sentence will not work"
rect area should be: 300.
```
Or you can stub **ANY message** to particular object:
```Smalltalk
mock := Mock new.
mock stub anyMessage willReturn: 100.
mock someMessage should be: 100.
mock someMessage2 should be: 100.
```
And both variants are supported:
```Smalltalk
Any stub anyMessage willReturn: 100.
mock := Mock new.
mock someMessage should be: 100.
rect := 0@0 corner: 2@3.
rect stub.
rect area should be: 100.
rect width should be: 100.
```
**Any** class is specific object spec which means "any" object\. You can uses any kind of specs:
```Smalltalk
(Kind of: Rectangle) stub width willReturn: 100.
rect := 0@0 corner: 2@3.
rect stub.
rect area should be: 300.
rect2 := 0@0 corner: 4@5.
rect2 stub.
rect2 area should be: 500
```
### Stub message sends with arguments
In place of message arguments you can use expected objects itself\. Or you can put specifications for expected arguments:
```Smalltalk
mock stub messageWith: arg1 and: arg2
mock stub messageWith: Any and: arg2
mock stub messageWith: [:arg | true]
mock stub messageWith: (Kind of: String) and: arg2
mock stub messageWith: (Instance of: Float) & (Satisfying for: [:arg | arg > 10]).
```
Last defined expectation has more priority than previous one\. It allows you to define default expectations in setUp method and override it in particular tests\. Following example shows it:
```Smalltalk
mock := Mock new.
(mock stub messageWith: (Instance of: SmallInteger)) willReturn: #anyInt.
(mock stub messageWith: (Kind of: String)) willReturn: #anyString.
(mock stub messageWith: 10) willReturn: #ten.
(mock messageWith: 10) should be: #ten.
(mock messageWith: 20) should be: #anyInt.
(mock messageWith: 'test') should be: #anyString
```
### Expected actions for stubs
There are different kind of expected actions:
```Smalltalk
mock := Mock new.
mock stub someMessage willReturn: #result.
mock someMessage should be: #result.
mock stub someMessage willRaise: ZeroDivide new.
[mock someMessage] should raise: ZeroDivide.
(mock stub someMessageWith: #arg) will: [#result].
(mock someMessageWith: #arg) should be: #result.
(mock stub someMessageWith: #arg1 and: #arg2) will: [:arg1 :arg2 | arg1, arg2].
(mock someMessageWith: #arg1 and: #arg2) should equal: 'arg1arg2'.
mock stub someMessage willReturnValueFrom: #(result1 result2).
mock someMessage should be: #result1.
mock someMessage should be: #result2
```
### Extra conditions on message sends
It is possible to verify arbitrary condition when expected message is going to be executed\. For example:
```Smalltalk
mock := Mock new.
mock stub someMessage
when: [flag] is: (Kind of: Boolean);
when: [flag] is: true;
when: [ flag ] satisfy: [ :object | true or: [ false ] ].
flag := true.
mock someMessage. "not failes"
flag := false.
mock someMessage "will fail immediately on call by last condition: flag should be true"
flag := #flag.
mock someMessage "will fail immediately on call by first condition: flag should be boolean"
```
Also Mocketry implements process related condition to check that message was synchronously sent \(relative to test process\):
```Smalltalk
mock stub someMessage shouldBeSentInThisProcess.
[ mock someMessage ] fork. "will fail immediately on call".
mock stub someMessage shouldBeSentInAnotherProcess.
[ mock someMessage ] fork. "will not fail".
mock someMessage. "will fail immediately on call"
```
### Message sends usage rules
It is possible to specify how much times expectation can be used:
```Smalltalk
mock := Mock new.
mock stub someMesage willReturn: #default.
mock stub someMessage willReturn: 300; use: 3.
mock stub someMessage willReturn: 200; useTwice.
mock stub someMesage willReturn: 100 useOnce.
"last defined expectation is more preferred then previously defined"
mock someMessage should be: 100.
mock someMessage should be: 200.
mock someMessage should be: 200.
mock someMessage should be: 300.
mock someMessage should be: 300.
mock someMessage should be: 300.
mock someMessage should be: #default
```
### Unexpected messages\. Automocks
Mock returns another special mock for unexpected messages \(when no expectation is defined for received message\):
```Smalltalk
mock := Mock new.
automock := mock someMessage.
automock should beInstanceOf: MockForMessageReturn.
```
And any message to this mock will produce another automock\.
It means that your tests will not fail if you will not define any expectation for your mocks\.
It allows you put only required detailes inside your tests which really make sense for tested aspect of functionality\. Anything else does not matters\.
Also to improve this idea automock try to play role of false in boolean expressions\.
```Smalltalk
mock := Mock new.
returnedMock := mock someMessage.
result := returnedMock ifFalse: [ #falseBranch ] ifTrue: [ #trueBranch ].
result should be: #falseBranch.
returnedMock should be: false
```
And play zero in arithmetic
```Smalltalk
mock := Mock new.
returnedMock := mock someMessage.
result := 1 + returnedMock.
result should equal: 1.
returnedMock should equal: 0
```
### Stub group of message sends
There is way to stub multiple message sends at once:
```Smalltalk
mock := Mock new.
rect := 0@0 corner: 2@3.
rect stub.
[ mock someMessage willReturn: 10.
rect width willReturn: 1000 ] should expect.
mock someMessage should be: 10.
rect area should be: 3000.
```
Inside "should expect" block you don't need to send **extra \#stub** message to objects
## Verify message sends
With Mocketry you can check that particular object received particular message\. Use **"should receive**" expression for this:
```Smalltalk
mock := Mock new.
mock someMessage.
mock should receive someMessage.
mock should not receive anotherMessage
```
You can verify that message was send to real objects\. It is not only about mocks:
```Smalltalk
rect := 0@0 corner: 2@3.
rect stub "it should be here to enable message interception"
rect area
rect should receive width. "area = width * height"
```
And you can do this with globals too:
```Smalltalk
Date