|
2 | 2 |
|
3 | 3 | ## Introduction
|
4 | 4 |
|
5 |
| -In these times the benefits of writing unit tests are huge. |
| 5 | +In these times, the benefits of writing unit tests are huge. |
6 | 6 | I think that most of the recently started projects contain any unit tests.
|
7 | 7 | In enterprise applications with a lot of business logic, unit tests are the most important tests,
|
8 | 8 | because they are fast and can us instantly assure that our implementation is correct.
|
9 |
| -However, I often see a problem with good tests in projects, though the benefits of these tests are only huge when you have good unit tests. |
| 9 | +However, I often see a problem with good tests in projects, though these tests' benefits are only huge when you have good unit tests. |
10 | 10 | So in these examples, I will try to share some tips on what to do to write good unit tests.
|
11 | 11 |
|
12 | 12 | ## Table of Contents
|
@@ -42,8 +42,6 @@ So in these examples, I will try to share some tips on what to do to write good
|
42 | 42 | 18. [100% Test Coverage shouldn't be the goal](#100-test-coverage-shouldnt-be-the-goal)
|
43 | 43 | 19. [Recommended books](#recommended-books)
|
44 | 44 |
|
45 |
| -## Introduction |
46 |
| - |
47 | 45 | ## Test doubles
|
48 | 46 |
|
49 | 47 | Test doubles are fake dependencies used in tests.
|
@@ -171,7 +169,7 @@ $mailer
|
171 | 169 | ```
|
172 | 170 |
|
173 | 171 | :exclamation:
|
174 |
| -To verify incoming interactions use a stub, but to verify outcoming interactions use a mock. |
| 172 | +To verify incoming interactions, use a stub, but to verify outcoming interactions, use a mock. |
175 | 173 | More: [Mock vs Stub](#mock-vs-stub)
|
176 | 174 |
|
177 | 175 | ## Naming
|
@@ -254,9 +252,9 @@ If your code is just a utility one it's less important.
|
254 | 252 | If there is a project with complex domain logic, this logic must be very clear for everyone,
|
255 | 253 | so then tests describe domain details without technical keywords, and you can talk with a business in a language like in these tests.
|
256 | 254 |
|
257 |
| -All code that is related to the domain should be free from technical details. A non-programmer won't be read these tests, |
258 |
| -but if you want to talk about the domain these tests will be useful to know what this domain does. |
259 |
| -There will be a description without technical details e.g. returns null, throws an exception, etc. |
| 255 | +All code that is related to the domain should be free from technical details. A non-programmer won't be read these tests. |
| 256 | +If you want to talk about the domain these tests will be useful to know what this domain does. |
| 257 | +There will be a description without technical details e.g., returns null, throws an exception, etc. |
260 | 258 | This kind of information has nothing to do with the domain, so we shouldn't use these keywords.
|
261 | 259 |
|
262 | 260 |
|
@@ -339,10 +337,9 @@ final class ExampleTest
|
339 | 337 |
|
340 | 338 | ## Parameterized test
|
341 | 339 |
|
342 |
| -The parameterized test is a good option to test the SUT with a lot of parameters without repeating the code. |
| 340 | +The parameterized test is a good option to test the SUT with many parameters without repeating the code. |
343 | 341 |
|
344 |
| -:thumbsdown: This kind of test is less readable. To increase the readability a little, negative and positive examples should be |
345 |
| -split up to different tests. |
| 342 | +:thumbsdown: This kind of test is less readable. To increase the readability a little, negative and positive examples should be split up to different tests. |
346 | 343 |
|
347 | 344 | ```php
|
348 | 345 | final class ExampleTest extends TestCase
|
@@ -453,7 +450,7 @@ final class TestExample extends TestCase
|
453 | 450 |
|
454 | 451 | [TODO]
|
455 | 452 |
|
456 |
| -## Mock vs Stub |
| 453 | +## Mock vs. Stub |
457 | 454 |
|
458 | 455 | Example:
|
459 | 456 | ```php
|
@@ -675,7 +672,7 @@ an infrastructure code related to a file system.**
|
675 | 672 |
|
676 | 673 | :heavy_check_mark: Good:
|
677 | 674 |
|
678 |
| -Like in the functional architecture we need to separate a code that has side effects and code which contains only logic. |
| 675 | +Like in functional architecture, we need to separate a code with side effects and code that contains only logic. |
679 | 676 |
|
680 | 677 | ```php
|
681 | 678 | final class NameParser
|
@@ -758,7 +755,7 @@ final class ValidUnitExampleTest extends TestCase
|
758 | 755 | }
|
759 | 756 | ```
|
760 | 757 |
|
761 |
| -## Observable behavior vs implementation details |
| 758 | +## Observable behavior vs. implementation details |
762 | 759 |
|
763 | 760 | :x: Bad:
|
764 | 761 |
|
@@ -957,8 +954,8 @@ final class ValidTestExample extends TestCase
|
957 | 954 | ```
|
958 | 955 |
|
959 | 956 | :information_source: The first subscription model has a bad design. To invoke one business operation you need to call three methods. Also using getters to verify operation is not a good practice.
|
960 |
| -In this case, it's skipped checking a change of modifiedAt, probably setting specific modifiedAt during a renew operation can be tested with an expiration business operation. The getter for modifiedAt is not required. |
961 |
| -Of course, there are cases where finding the possibility to avoid getters provided only for tests will be very hard, but always we should try to not introduce them. |
| 957 | +In this case, it's skipped checking a change of `modifiedAt`, probably setting specific `modifiedAt` during a renew operation can be tested with an expiration business operation. The getter for `modifiedAt` is not required. |
| 958 | +Of course, there are cases where finding the possibility to avoid getters provided only for tests will be very hard, but always we should try not to introduce them. |
962 | 959 |
|
963 | 960 | ## Unit of behavior
|
964 | 961 |
|
@@ -1213,7 +1210,7 @@ class SubscriptionTest extends TestCase
|
1213 | 1210 | }
|
1214 | 1211 | ```
|
1215 | 1212 |
|
1216 |
| -:exclamation: **Do not write code 1:1, 1 class : 1 test. It leads to fragile tests which make that refactoring is very hard.** |
| 1213 | +:exclamation: **Do not write code 1:1, 1 class : 1 test. It leads to fragile tests which make that refactoring is tough.** |
1217 | 1214 |
|
1218 | 1215 | :heavy_check_mark: Good:
|
1219 | 1216 |
|
@@ -1689,7 +1686,7 @@ final class TestUserRepository extends TestCase
|
1689 | 1686 | }
|
1690 | 1687 | ```
|
1691 | 1688 |
|
1692 |
| -:exclamation: Testing repositories in that way leads to fragile tests and then refactoring is very hard. To test repositories write integration tests. |
| 1689 | +:exclamation: Testing repositories in that way leads to fragile tests and then refactoring is tough. To test repositories write integration tests. |
1693 | 1690 |
|
1694 | 1691 | ## Test fixtures
|
1695 | 1692 |
|
@@ -1891,8 +1888,7 @@ final class ValidTest extends TestCase
|
1891 | 1888 | ```
|
1892 | 1889 |
|
1893 | 1890 | :exclamation: Adding additional production code (e.g. getter getCustomerType()) only to verify the state in tests is a bad practice.
|
1894 |
| -It should be verified by another domain significant value (in this case getPercentageDiscount()). Of course, sometimes it can be very hard |
1895 |
| -to find another way to verify the operation, and we can be forced to add additional production code to verify correctness in tests, but we should try to avoid that. |
| 1891 | +It should be verified by another domain significant value (in this case getPercentageDiscount()). Of course, sometimes it can be tough to find another way to verify the operation, and we can be forced to add additional production code to verify correctness in tests, but we should try to avoid that. |
1896 | 1892 |
|
1897 | 1893 | ### Leaking domain details
|
1898 | 1894 |
|
@@ -2210,7 +2206,7 @@ final class ValidTest extends TestCase
|
2210 | 2206 |
|
2211 | 2207 | ### Time as a volatile dependency
|
2212 | 2208 |
|
2213 |
| -:information_source: The time is a volatile dependency because is non-deterministic, each invocation returns a different result. |
| 2209 | +:information_source: The time is a volatile dependency because it is non-deterministic. Each invocation returns a different result. |
2214 | 2210 |
|
2215 | 2211 | :x: Bad:
|
2216 | 2212 |
|
|
0 commit comments