Advertisement
Guest User

Untitled

a guest
Aug 20th, 2019
103
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.98 KB | None | 0 0
  1. **Bad practices** I want to avoid by this guidelines:
  2. 1. Creating a separate test **class for one test case**. (It is left mostly from the `unittest` times.)
  3. 2. Creating test cases for **different** module-level **methods** under the **same** test **class**. (See reason #1. Then developer just copy-paste existing testcase to create a new method test case (which is ok) and place it under an existing test class (which is not ok))
  4. 3. **Duplicating method name** from test class in the test case name. Like this: `TestMyMethod->test_my_method_positive, test_my_method_negative` (DRY. Once you've created a test class for only one method there is no need to duplicate its name in the `test_method` name)
  5. 4. Method name being written with a **scenario name without a separator**. (Consider name like `test_series_length_is_more_than_10`. It doesn't look too bad until you consider that there are 2 methods in the module:
  6.  
  7. * `series_length(series)->int`
  8. * `series_length_is_more_than(series, int)->bool`
  9.  
  10.  
  11. Double uderscore makes things clear: where method name ends and test case description starts:
  12.  
  13. * `test_series_length__is_more_than_10`
  14. * `test_series_length_is_more_than__10`
  15.  
  16.  
  17. ## Suggested guidelines
  18.  
  19. **1. Test module has the same path as the source module.** E.g.: `ModelingMachine/worker.py` -> `ModelingMachine/test__worker.py`
  20.  
  21. **2. Keep test (and source) files shorter than 1000 lines.** If it grows too big (not decided):
  22. * create new files with `__description_in_the_name` (plain is better than nested). E.g.:
  23. * `ModelingMachine/worker.py (ModelingMachineWorkerProcess class)` -> `ModelingMachine/test__worker__modeling_machine_worker_process.py`
  24. * `ModelingMachine/worker.py (ProcessUpdater class)` -> `ModelingMachine/test__worker__process_updater.py`
  25. * `ModelingMachine/worker.py (SecureWorkerProcess class)` -> `ModelingMachine/test__worker__secure_worker_process.py`
  26. * `ModelingMachine/worker.py (the rest)` -> `ModelingMachine/test__worker.py`
  27.  
  28. * create a new package. (source module can be divided later the same way) E.g.:
  29. * `ModelingMachine/worker.py (ModelingMachineWorkerProcess class)` -> `ModelingMachine/worker/test__common.py`
  30. * `ModelingMachine/worker.py (ProcessUpdater class)` -> `ModelingMachine/worker/test__modeling_machine_worker_process.py`
  31. * `ModelingMachine/worker.py (SecureWorkerProcess class)` -> `ModelingMachine/worker/test__process_updater.py`
  32. * `ModelingMachine/worker.py (the rest)` -> `ModelingMachine/worker/test__secure_worker_process.py`
  33.  
  34. **3. Structure of the test file**:
  35. * Module-level methods are tested with module-level test cases.
  36. * Class-level methods are tested with class-level test cases.
  37.  
  38. but
  39.  
  40. * you can create a separate class for a complex method to keep file structured.
  41.  
  42.  
  43. **4. Testcase method name structure**: `def test_{method name}__{scenario description}__{expected result}(...)`:
  44.  
  45. `{method name}` - required.
  46.  
  47. `{scenario description}` - required if there are multiple test cases for a method.
  48.  
  49. `{expected result}` - strongly suggested if there are >5 scenarios for a method.
  50.  
  51.  
  52. ```
  53. --- original_file.py ---
  54.  
  55. def simple_method():
  56. ...
  57.  
  58. def standard_method():
  59. # positive -> 0
  60. # negative -> 1
  61.  
  62. def complex_method():
  63. # -> {"status": 0, "message": "ok"}
  64. # -> {"status": 10, "message": "Need info"}
  65. # -> {"status": 20, "message": "Permission Denied"}
  66. # -> {"status": 100, "message": "Error"}
  67.  
  68. class A:
  69. def do_something():
  70. ...
  71.  
  72. def do_another_thing():
  73. ...
  74.  
  75. def method_with_extremely_complex_logic_avoid_creating_such_methods():
  76. ...
  77.  
  78. ```
  79.  
  80. ```
  81. --- test_original_file.py ---
  82.  
  83. # Keep simple things simple. One test case can be enough.
  84. def test_simple_method():
  85. ...
  86.  
  87.  
  88. # It is not required to specify expected result but you make the world better by doing this.
  89. def test_standard_method__positive__0():
  90. ...
  91.  
  92.  
  93. def test_standard_method__negative__1():
  94. ...
  95.  
  96.  
  97. # Some *invalid input* will be provided for the *standard_method*. It is expected to raise *ValueError*.
  98. def test_standard_method__invalid_input__value_error():
  99. ...
  100.  
  101.  
  102. class TestComplexMethod(object):
  103. def test_positive__status_0():
  104. ....
  105.  
  106. def test_no_phone__status_10():
  107. ....
  108.  
  109. def test_wrong_user__status_20():
  110. ....
  111.  
  112. def test_user_does_not_exist__status_100():
  113. ....
  114.  
  115.  
  116. class TestA(object):
  117. def test_do_something():
  118. ...
  119.  
  120. # You can skip test casse description for default/positive scenario.
  121. def test_do_another_thing():
  122. ...
  123.  
  124. def test_do_another_thing__wrong_state__value_error():
  125. ...
  126.  
  127.  
  128. class TestAMethodWithExtremelyComplexLogicAvoidCreatingSuchMethods(object):
  129. # Class name already contains both source class name and source method name.
  130. # Method name is skipped in the test case method name.
  131. def test_description_1__expected_output_or_side_efect_1():
  132. ...
  133.  
  134. def test_description_2__expected_output_or_side_efect_2():
  135. ...
  136.  
  137. ...
  138.  
  139. def test_description_n__expected_output_or_side_efect_n():
  140. ...
  141.  
  142. ```
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement