From 26a53db2eff8ac3c15a28fd715fd29219302bd96 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Tue, 8 Oct 2024 12:30:59 +0200 Subject: [PATCH] gram --- ...ade-deprecated-phpunit-with-consecutive.md | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/resources/posts/2024/2024-10-08-how-to-upgrade-deprecated-phpunit-with-consecutive.md b/resources/posts/2024/2024-10-08-how-to-upgrade-deprecated-phpunit-with-consecutive.md index 667311a026b..9b64e75cf34 100644 --- a/resources/posts/2024/2024-10-08-how-to-upgrade-deprecated-phpunit-with-consecutive.md +++ b/resources/posts/2024/2024-10-08-how-to-upgrade-deprecated-phpunit-with-consecutive.md @@ -4,12 +4,12 @@ title: "How to Upgrade deprecated PHPUnit withConsecutive()" perex: | The `withConsecutive()` method [was deprecated in PHPUnit 9](https://github.com/sebastianbergmann/phpunit/issues/4255#issuecomment-636422439) and removed in PHPUnit 10. It sparked many [questions](https://stackoverflow.com/questions/75389000/replace-phpunit-method-withconsecutive-abandoned-in-phpunit-10), [on StackOverflow](https://stackoverflow.com/questions/77865216/phpunit-withconsecutive-is-gone-what-is-the-recommended-approach), in [various projets](https://www.drupal.org/project/drupal/issues/3306554) and [GitHub](https://github.com/search?q=repo%3Asebastianbergmann%2Fphpunit+withConsecutive&type=issues). - It was not very popular BC break. There is no 1:1 replacement. It can be combined with `willReturn*()` methods and that can make it even more tricky to merge with. + It was not a very popular BC break. There is no 1:1 replacement. It can be combined with `willReturn*()` methods, which can make it even more tricky to merge with. - PHPUnit upgrades take 95 % of time just to upgrade this single method, and 5 % about everything else. - Recent months we've done couple of project upgrades with Rector and we've learned a lot. + PHPUnit upgrades take 95 % of the time to upgrade this single method and 5 % for everything else. + In recent months, we've done a couple of project upgrades with Rector and learned a lot. - Today, I want to share bit of knowledge with you and explain, **why it's a change for better code**. + Today, I want to share some knowledge with you and explain why it's a change for better code. --- What does `withConsecutive()` method actually do? @@ -24,17 +24,17 @@ $mock->expects($this->exactly(2)) ); ``` -It defines what arguments are on the input, once the method mock is called. E.g. here: +It defines what arguments are on the input once the method mock is called. E.g. here: * on 1st call, it expects `['first']` * on 2nd call, it expects `['second']` -To be honest, I've never wrote such code myself, but so far we found it in every code base we've upgraded. -It's been available since 2006, and only removed after 16 years in 2022. +To be honest, I've never written such code myself, but so far, we've found it in every code base we've upgraded. +It's been available since 2006 and only removed after 16 years in 2022.
-So how can be replace it? It would be very convenient, if there would some kind of `withNthCall()` method: +So how can we replace it? It would be very convenient if there would some kind of `withNthCall()` method: ```php $mock = $this->createMock(MyClass::class); @@ -49,7 +49,7 @@ But it's not. ## `withCallable()` to the Rescue -Instead we use `withCallable()` trick. This methods accepts the called parameters, that we can assert inside. +Instead, we use the `withCallable()` trick. This method accepts the called parameters, which we can assert inside. ```php $mock = $this->createMock(MyClass::class); @@ -60,7 +60,7 @@ $mock->expects($this->exactly(2)) }); ``` -But how do we detect, if it's the 1st or 2nd call? The `$this->exactly(2)` expression actually returns a value object `PHPUnit\Framework\MockObject\Rule\InvokedCount` that we can work with. +But how do we detect if it's the first or second call? The `$this->exactly(2)` expression actually returns a value object `PHPUnit\Framework\MockObject\Rule\InvokedCount` that we can work with. ```php $invokedCount = $this->exactly(2); @@ -73,7 +73,7 @@ $mock->expects($invokedCount) }); ``` -On every method mock invoke, the number of invokes in `$invokedCount` will get increased. +On every mock invoke method, the number of invokes in `$invokedCount` will increase.
@@ -96,7 +96,7 @@ $mock->expects($invokedCount) }); ``` -Now we include original parameters we needed it: +Now we include the original parameters we needed: ```php // ... @@ -112,7 +112,7 @@ Now we include original parameters we needed it: }); ``` -Now this where this deprecation becomes useful. What if one of parameters is an product object? +Now, this is where this deprecation becomes useful. What if one of the parameters is a product object? We could create a `$product` object and do `assertSame()`. But what if we only care about its price? @@ -129,28 +129,28 @@ We could create a `$product` object and do `assertSame()`. But what if we only c }); ``` -This would turn into single-line mess using `withConsecutive()`. Now it's more readable and flexible. +Using `withConsecutive()` would turn this into a single-line mess. Now, it's more readable and flexible.
## Why `if` over `match`? -Originally, we used `match()` expression over `ifs()` in Rector rule, but it created couple of new problems: +Originally, we used the `match()` expression over `ifs()` in the Rector rule, but it created a couple of new problems: * PHPUnit 9.x requires PHP 7.3+. Using `match()` would mean you have to do the upgrade to PHP 8 and to PHPUnit 10 at the same time. This is not always possible and can be risky * The call count is already checked by `$this->exactly(2)`. There is no need to add another layer of complexity to check the same thing again -* With `match()` there is only single line of expression. Assert above would be single line: +* With `match()`, there is only a single line of expression. Assert above would be a single line: ```php => $product = $parameters[0] && $this->assertInstanceof(Product::class, $product) && $this->assertSame(100, $product->getPrice()) ``` -Which is not readable and maintainable. There is also one more reason why `if()` is the king. +This code is not readable and maintainable. There is also one more reason why `if()` is the king. ## Return value -More often than not, the method not only accepts parameters, but also return some value. That's where `willReturn*()` methods come into play: +More often than not, the method not only accepts parameters but also returns some value. That's where `willReturn*()` methods come into play: ```php $mock = $this->createMock(MyClass::class); @@ -209,17 +209,17 @@ We can just write plain PHP code: ## More Readable and Easier to Maintain -* We don't have to learn special PHPUnit mock method naming and we can understand the code. -* This vanilla PHP also opens up next step - refactoring [away from mocks to anonymous typed classes](/blog/2018/06/11/how-to-turn-mocks-from-nightmare-to-solid-kiss-tests) -* We can easily add new assertion line +* We don't have to learn special PHPUnit mock method naming and can understand the code. +* This vanilla PHP also opens up the next step - refactoring [away from mocks to anonymous typed classes](/blog/2018/06/11/how-to-turn-mocks-from-nightmare-to-solid-kiss-tests) +* We can easily add a new assertion line * We can return values we need -What if in upcoming PHPUnit 12, 13, 14... versions some of mocking methods will be changed or removed? This code will most likely work, as it's just plain PHP. +What if, in the upcoming PHPUnit 12, 13, and 14... versions, remove or change more mocking methods? This code will work, as it's just plain PHP.
-This is how we can upgrade `withConsecutive()` method in PHPUnit 9 or earlier. I hope it's more clear now why this change was needed, and how it can help you write better tests. +This is how we can upgrade the `withConsecutive()` method in PHPUnit 9 or earlier. I hope it's clearer now why this change was needed and how it can help you write better tests.