@@ -4,39 +4,89 @@ Unit tests should use descriptive, behavior-driven naming with the `it_should_`
44
55## Naming Convention
66
7- - ** Format** : ` it_should_{describe_expected_behavior } `
7+ - ** Format** : ` it_should_{expected_behavior}_when_{condition} ` or ` it_should_{expected_behavior}_given_{state }`
88- ** Style** : Use lowercase with underscores, be descriptive and specific
9- - ** Focus** : Describe what the test validates, not just what function it calls
9+ - ** Structure** : Follow the three-part pattern (What-When-Then)
10+
11+ ### The Three-Part Structure
12+
13+ Every test name should clearly communicate:
14+
15+ 1 . ** What** - The expected behavior or outcome being tested
16+ 2 . ** When** - The triggering condition or scenario (use ` when_ ` or ` given_ ` )
17+ 3 . ** Context** - Implicit from the test module/struct being tested
18+
19+ This follows established conventions from:
20+
21+ - ** Roy Osherove's standard** : ` UnitOfWork_StateUnderTest_ExpectedBehavior `
22+ - ** BDD Given-When-Then** : Behavior-driven development naming
23+ - ** AAA Pattern** : Arrange-Act-Assert reflected in test names
24+
25+ ### Key Properties of Good Test Names
26+
27+ A well-named test should tell you:
28+
29+ - ✅ ** What behavior** is being validated (the expected outcome)
30+ - ✅ ** When it happens** (the triggering condition or preconditions)
31+ - ✅ ** What's being tested** (implicit from module context, or explicit in name)
32+ - ✅ ** Why it matters** (clear from the behavior description)
33+
34+ ### Guidelines
35+
36+ - ** Be specific about conditions** : Use ` when_ ` , ` given_ ` , ` with_ ` , or ` for_ ` to describe the scenario
37+ - ** Describe behavior, not implementation** : Focus on what happens, not how
38+ - ** Use complete phrases** : Test names can be long - clarity beats brevity
39+ - ** Include edge cases explicitly** : ` when_input_is_empty ` , ` when_value_exceeds_limit `
40+ - ** Describe error conditions clearly** : ` when_file_not_found ` , ` given_invalid_format `
1041
1142## Examples
1243
13- ### ✅ Good Test Names
44+ ### ✅ Good Test Names (Following Three-Part Structure)
1445
1546``` rust
1647#[test]
17- fn it_should_create_ansible_host_with_valid_ipv4 () {
48+ fn it_should_create_valid_host_when_given_ipv4_address () {
49+ // What: create valid host | When: given IPv4 address
1850 let ip = IpAddr :: V4 (Ipv4Addr :: new (192 , 168 , 1 , 1 ));
1951 let host = AnsibleHost :: new (ip );
2052 assert_eq! (host . as_ip_addr (), & ip );
2153}
2254
2355#[test]
24- fn it_should_fail_with_invalid_ip_address () {
56+ fn it_should_return_error_when_parsing_invalid_ip_string () {
57+ // What: return error | When: parsing invalid IP string
2558 let result = AnsibleHost :: from_str (" invalid.ip.address" );
2659 assert! (result . is_err ());
2760}
2861
2962#[test]
30- fn it_should_serialize_to_json () {
63+ fn it_should_serialize_to_json_string_when_valid_host_exists () {
64+ // What: serialize to JSON | When: valid host exists
3165 let host = AnsibleHost :: from_str (" 192.168.1.1" ). unwrap ();
3266 let json = serde_json :: to_string (& host ). unwrap ();
3367 assert_eq! (json , " \ " 192.168.1.1\ "" );
3468}
69+
70+ #[test]
71+ fn it_should_reject_environment_name_when_containing_uppercase_letters () {
72+ // What: reject name | When: containing uppercase
73+ let result = EnvironmentName :: new (" MyEnv" . to_string ());
74+ assert! (matches! (result , Err (ValidationError :: InvalidCharacters )));
75+ }
76+
77+ #[test]
78+ fn it_should_preserve_order_when_deserializing_from_json () {
79+ // What: preserve order | When: deserializing from JSON
80+ let json = r # " {"first": 1, "second": 2}" # ;
81+ let config : Config = serde_json :: from_str (json ). unwrap ();
82+ assert_eq! (config . keys (). collect :: <Vec <_ >>(), vec! [" first" , " second" ]);
83+ }
3584```
3685
3786### ❌ Avoid These Test Names
3887
3988``` rust
89+ // ❌ Too generic - doesn't describe behavior or condition
4090#[test]
4191fn test_new () { /* ... */ }
4292
@@ -45,11 +95,174 @@ fn test_from_str() { /* ... */ }
4595
4696#[test]
4797fn test_serialization () { /* ... */ }
98+
99+ // ❌ Focuses on implementation, not behavior
100+ #[test]
101+ fn it_should_call_validate_method () { /* ... */ }
102+
103+ #[test]
104+ fn it_should_use_serde_deserialize () { /* ... */ }
105+
106+ // ❌ Missing condition/scenario context
107+ #[test]
108+ fn it_should_fail () { /* What fails? When? Why? */ }
109+
110+ #[test]
111+ fn it_should_return_value () { /* Which value? Under what conditions? */ }
112+
113+ // ❌ Too vague about expected behavior
114+ #[test]
115+ fn it_should_work_correctly () { /* What does "work correctly" mean? */ }
116+
117+ #[test]
118+ fn it_should_handle_edge_case () { /* Which edge case? How is it handled? */ }
119+ ```
120+
121+ ### Pattern Examples by Category
122+
123+ #### Success Cases
124+
125+ ``` rust
126+ it_should_create_environment_when_given_valid_name ()
127+ it_should_return_formatted_output_when_data_is_complete ()
128+ it_should_preserve_state_when_serializing_and_deserializing ()
129+ ```
130+
131+ #### Error Cases
132+
133+ ``` rust
134+ it_should_return_error_when_file_does_not_exist ()
135+ it_should_reject_config_when_required_field_is_missing ()
136+ it_should_fail_validation_when_port_exceeds_maximum ()
137+ ```
138+
139+ #### Edge Cases
140+
141+ ``` rust
142+ it_should_handle_empty_string_when_parsing_optional_field ()
143+ it_should_return_default_when_environment_variable_is_unset ()
144+ it_should_allow_maximum_length_when_validating_string_input ()
145+ ```
146+
147+ #### State Transitions
148+
149+ ``` rust
150+ it_should_transition_to_active_when_provisioning_completes ()
151+ it_should_remain_in_pending_state_when_validation_fails ()
152+ it_should_rollback_to_previous_state_when_operation_errors ()
153+ ```
154+
155+ ## Common Anti-Patterns to Avoid
156+
157+ ### ❌ Testing Implementation Details
158+
159+ ``` rust
160+ // Bad: Tests how something is done
161+ it_should_call_repository_save_method ()
162+
163+ // Good: Tests what happens
164+ it_should_persist_environment_when_creation_succeeds ()
165+ ```
166+
167+ ### ❌ Vague Conditions
168+
169+ ``` rust
170+ // Bad: Unclear when this happens
171+ it_should_fail_validation ()
172+
173+ // Good: Specific condition
174+ it_should_fail_validation_when_port_number_is_negative ()
48175```
49176
177+ ### ❌ Missing Expected Outcome
178+
179+ ``` rust
180+ // Bad: Doesn't state what happens
181+ it_should_process_input_when_valid ()
182+
183+ // Good: Clear outcome
184+ it_should_return_parsed_config_when_input_is_valid_json ()
185+ ```
186+
187+ ### ❌ Technical Jargon Without Context
188+
189+ ``` rust
190+ // Bad: Requires domain knowledge to understand
191+ it_should_deserialize_dto ()
192+
193+ // Good: Explains the behavior
194+ it_should_convert_json_to_environment_config_when_deserializing ()
195+ ```
196+
197+ ## Best Practices
198+
199+ ### Do's ✅
200+
201+ - ** Use complete phrases** : ` when_given_empty_string ` not ` when_empty `
202+ - ** Be explicit about data states** : ` when_file_does_not_exist ` not ` when_no_file `
203+ - ** Describe outcomes clearly** : ` should_return_error ` not ` should_fail `
204+ - ** Include relevant values** : ` when_port_exceeds_65535 ` not ` when_port_too_large `
205+ - ** Name error types** : ` should_return_validation_error ` not ` should_return_error `
206+
207+ ### Don'ts ❌
208+
209+ - ** Don't test methods directly** : Test behaviors, not function names
210+ - ** Don't use abbreviations** : ` when_cfg_invalid ` → ` when_configuration_is_invalid `
211+ - ** Don't skip the condition** : Always include the ` when_ ` or ` given_ ` clause
212+ - ** Don't be overly technical** : Focus on business behavior, not implementation
213+ - ** Don't make assumptions** : Be explicit about preconditions
214+
215+ ## Reading Your Test Names
216+
217+ A good test name should read naturally as a sentence when you add spaces:
218+
219+ - ❌ ` test_parse_error ` → "test parse error" (unclear)
220+ - ✅ ` it_should_return_error_when_parsing_invalid_json ` → "it should return error when parsing invalid JSON" (clear)
221+
50222## Benefits
51223
52- - ** Clarity** : Test names clearly describe the expected behavior
53- - ** Documentation** : Tests serve as living documentation of the code's behavior
54- - ** BDD Style** : Follows Behavior-Driven Development naming conventions
55- - ** Maintainability** : Easier to understand test failures and purpose
224+ - ** Clarity** : Test names clearly describe the expected behavior and conditions
225+ - ** Documentation** : Tests serve as living, executable specifications of behavior
226+ - ** BDD Style** : Follows established Behavior-Driven Development conventions
227+ - ** Maintainability** : Easier to understand test failures and identify affected behavior
228+ - ** Traceability** : Clear mapping between requirements/behaviors and tests
229+ - ** Debugging** : Failed test names immediately tell you what broke and under what conditions
230+ - ** Code Reviews** : Reviewers can understand test purpose without reading implementation
231+
232+ ## Quick Reference
233+
234+ ### Test Name Template
235+
236+ ``` rust
237+ it_should_ {expected_behavior }_when_ {triggering_condition }
238+ it_should_ {expected_behavior }_given_ {initial_state }
239+ ```
240+
241+ ### Checklist for Good Test Names
242+
243+ - [ ] Describes the ** expected behavior** clearly
244+ - [ ] Specifies the ** triggering condition** or scenario
245+ - [ ] Uses complete phrases, not abbreviations
246+ - [ ] Reads naturally as a sentence
247+ - [ ] Focuses on ** what** happens, not ** how**
248+ - [ ] Includes specific values or states when relevant
249+ - [ ] Is specific enough to understand without reading the test body
250+
251+ ## References and Further Reading
252+
253+ This guide is based on established testing conventions and best practices:
254+
255+ - ** Roy Osherove's Naming Standard** : "The Art of Unit Testing" - The three-part naming pattern: ` UnitOfWork_StateUnderTest_ExpectedBehavior `
256+ - ** BDD (Behavior-Driven Development)** : Dan North's Given-When-Then pattern for describing behavior
257+ - ** AAA Pattern** : Arrange-Act-Assert structure reflected in test organization and naming
258+ - ** Google Testing Blog** : Best practices for test naming and structure
259+ - ** Martin Fowler** : Testing patterns and behavior-focused naming
260+ - ** Kent Beck** : Test-Driven Development principles
261+
262+ ### External Resources
263+
264+ - [ The Art of Unit Testing (Roy Osherove)] ( https://www.artofunittesting.com/ )
265+ - [ BDD Fundamentals (Dan North)] ( https://dannorth.net/introducing-bdd/ )
266+ - [ Google Testing Blog] ( https://testing.googleblog.com/ )
267+ - [ xUnit Test Patterns] ( http://xunitpatterns.com/ )
268+ - [ Growing Object-Oriented Software, Guided by Tests] ( http://www.growing-object-oriented-software.com/ )
0 commit comments