Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,68 @@ jobs:
- name: Install the engine from a dist archive and use it
run: bin/consumer-smoke --only=core

adapters:
name: Adapter contract suite (${{ matrix.adapter }})
# Keep this matrix unconditional. A matrix job skipped by its own `if:`
# reports one raw check name instead of the expanded names that branch
# protection requires, leaving each adapter context pending on docs-only
# changes. The four adapter suites are cheap compared with mutation.
runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
adapter:
- testo
- psalm
- phpunit
- phpstan

steps:
- name: Checkout core
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
path: core

- name: Checkout adapter
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
repository: rasuvaeff/understudy-${{ matrix.adapter }}
persist-credentials: false
path: adapter

- name: Setup PHP
uses: shivammathur/setup-php@f3e473d116dcccaddc5834248c87452386958240 # v2
with:
php-version: '8.4'
coverage: none
extensions: json, mbstring
tools: composer:v2

- name: Cache Composer dependencies
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.composer/cache
key: composer-${{ runner.os }}-${{ hashFiles('**/composer.json') }}
restore-keys: composer-${{ runner.os }}-

- name: Point the adapter at this checkout of core
working-directory: adapter
run: |
composer config repositories.core '{"type":"path","url":"../core","options":{"versions":{"rasuvaeff/understudy":"1.0.0"}}}'
composer update --no-interaction --no-progress

- name: Verify core resolved to the path repository
working-directory: adapter
run: |
composer show rasuvaeff/understudy | tee /tmp/core-source.txt
grep -qE '^path +: +' /tmp/core-source.txt

- name: Adapter test suite
working-directory: adapter
run: composer test

coverage:
name: Coverage & Mutation
needs: changes
Expand Down
25 changes: 12 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,30 +69,29 @@ here. Two rows are traps, marked ⚠.

## Performance

Against Mockery 1.6.15, Prophecy 1.26.1 and PHPUnit 12.5.33 on PHP 8.5.6.
Against Mockery 1.6.15, Prophecy 1.26.1 and PHPUnit 12.5.36 on PHP 8.5.6.
Filtered means, three runs; understudy is the baseline. Full methodology, raw
tables and the environment in [perf/README.md](perf/README.md).

| | understudy | Mockery | Prophecy | PHPUnit |
|---|---|---|---|---|
| build a double (1-method contract) | **2.06µs** | +216% | +683% | +155%¹ |
| build a double (8-method contract) | **2.06µs** | +217% | +641% | +158%¹ |
| stub: build, stub, one call, tear down | 10.6µs | +17% | +76% | **−17%**¹ |
| mock: build, expect, call, verify | 12.8µs | +4% | +128% | **−27%**² |
| marginal cost of one call to a stub | 0.86µs | 1.61µs | 1.51µs | **0.69µs**¹ |
| added to process start (cold) | **1.00×** | 1.50× | 4.96× | 5.38³ |
| retained per live double | **467–482 B** | 513 B | ~8.5 KB | ~1.25 KB |
| build a double (1-method contract) | **2.69µs** | +148% | +497% | +102%¹ |
| build a double (8-method contract) | **2.67µs** | +149% | +478% | +104%¹ |
| stub: build, stub, one call, tear down | 12.8µs | −8% | +33% | **−34%**¹ |
| mock: build, expect, call, verify | 16.0µs | −16% | +89% | **−41%**² |
| marginal cost of one call to a stub | 1.02µs | 1.62µs | 1.50µs | **0.70µs**¹ |
| added to process start (cold) | **1.00×** | 0.96× | 2.69× | 2.91³ |
| retained per live double | **571–586 B** | 513 B | ~8.5 KB | ~1.25 KB |

¹ `createStub()` ² `createMock()` ³ a ratio rather than milliseconds: cold start
moves far more between runs than its ratios do.

Understudy builds doubles about two and a half times cheaper than the next
fastest, and starts a process in a fifth of the added time. It does **not** win
everywhere: PHPUnit is ahead on both stub and mock scenarios end to end — it
dispatches a call in 0.69µs against understudy's 0.86µs and no longer pays
enough at build time to make up for it.
fastest. It does **not** win everywhere: PHPUnit is ahead on both stub and mock
scenarios end to end — it dispatches a call in 0.70µs against understudy's
1.02µs, and Mockery is marginally faster on cold start in this release run.

**Building a double costs more than it did**, 2.06µs against 1.28µs in the
**Building a double costs more than it did**, 2.69µs against 1.28µs in the
figures published with 0.1.x. Those figures were taken at a commit *before*
0.1.0 and described no released version: a regression landed between them and
the first tag, and has been shipping since. It is bisected and documented in
Expand Down
22 changes: 11 additions & 11 deletions README.ru.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,24 +75,24 @@ when(fn () => $repository->find(123))->returns($book);

| | understudy | Mockery | Prophecy | PHPUnit |
|---|---|---|---|---|
| создать дубль (контракт из 1 метода) | **2.06µs** | +216% | +683% | +155%¹ |
| создать дубль (контракт из 8 методов) | **2.06µs** | +217% | +641% | +158%¹ |
| stub: создать, застабить, вызвать, снести | 10.6µs | +17% | +76% | **−17%**¹ |
| mock: создать, expect, вызвать, verify | 12.8µs | +4% | +128% | **−27%**² |
| предельная цена одного вызова к стабу | 0.86µs | 1.61µs | 1.51µs | **0.69µs**¹ |
| добавляет к старту процесса (холодный) | **1.00×** | 1.50× | 4.96× | 5.38³ |
| удерживает на каждый живой дубль | **467–482 B** | 513 B | ~8.5 KB | ~1.25 KB |
| создать дубль (контракт из 1 метода) | **2.69µs** | +148% | +497% | +102%¹ |
| создать дубль (контракт из 8 методов) | **2.67µs** | +149% | +478% | +104%¹ |
| stub: создать, застабить, вызвать, снести | 12.8µs | −8% | +33% | **−34%**¹ |
| mock: создать, expect, вызвать, verify | 16.0µs | −16% | +89% | **−41%**² |
| предельная цена одного вызова к стабу | 1.02µs | 1.62µs | 1.50µs | **0.70µs**¹ |
| добавляет к старту процесса (холодный) | **1.00×** | 0.96× | 2.69× | 2.91³ |
| удерживает на каждый живой дубль | **571–586 B** | 513 B | ~8.5 KB | ~1.25 KB |

¹ `createStub()` ² `createMock()` ³ отношение, а не миллисекунды: холодный
старт разбегается между прогонами куда сильнее, чем его отношения.

Understudy создаёт дубли примерно в два с половиной раза дешевле ближайшего и
добавляет к старту процесса впятеро меньше. Выигрывает он **не везде**:
Understudy создаёт дубли примерно в два с половиной раза дешевле ближайшего.
Выигрывает он **не везде**:
PHPUnit впереди и на stub-, и на mock-сценарии целиком — он диспетчеризует
вызов за 0.69µs против 0.86µs у understudy и больше не платит на создании
вызов за 0.70µs против 1.02µs у understudy и больше не платит на создании
столько, чтобы это перекрыть.

**Создание дубля стоит дороже, чем раньше** — 2.06µs против 1.28µs в цифрах,
**Создание дубля стоит дороже, чем раньше** — 2.69µs против 1.28µs в цифрах,
опубликованных с 0.1.x. Те цифры сняты на коммите *до* 0.1.0 и не описывали ни
одну выпущенную версию: между ними и первым тегом приехала регрессия, которая с
тех пор и отгружается. Она локализована бисектом и описана в
Expand Down
10 changes: 5 additions & 5 deletions docs/.api-workspace/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@
"require": {
"php": "8.3 - 8.5",
"phpdocumentor/reflection-docblock": "^5.6",
"rasuvaeff/understudy-phpstan": "^0.5",
"rasuvaeff/understudy-phpunit": "^0.5",
"rasuvaeff/understudy-psalm": "^0.8",
"rasuvaeff/understudy-testo": "^0.3"
"rasuvaeff/understudy-phpstan": "^1.0",
"rasuvaeff/understudy-phpunit": "^1.0",
"rasuvaeff/understudy-psalm": "^1.0",
"rasuvaeff/understudy-testo": "^1.0"
},
"repositories": [
{
"type": "path",
"url": "../..",
"options": {
"versions": {
"rasuvaeff/understudy": "0.9.0"
"rasuvaeff/understudy": "1.0.0"
}
}
}
Expand Down
54 changes: 27 additions & 27 deletions docs/.api-workspace/composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading