Skip to content

Commit 912e7b5

Browse files
committed
mockist slides
1 parent 13ead04 commit 912e7b5

1 file changed

Lines changed: 118 additions & 45 deletions

File tree

presentation/slides.md

Lines changed: 118 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -430,34 +430,6 @@ layout: two-col-image-text
430430

431431
![](./images/meme-test-doubles.jpg)
432432

433-
---
434-
layout: default-aside
435-
size: lg
436-
h1:
437-
type: brackets
438-
color: muted
439-
position: all
440-
---
441-
442-
# State vs Behavior
443-
444-
<v-clicks>
445-
446-
- **State Testing**
447-
- Validate that a property has a certain value
448-
- **Behavior Testing**
449-
- Validate that a method was (not) called
450-
451-
</v-clicks>
452-
453-
::image::
454-
455-
![](./images/circle-crown.jpg)
456-
457-
<!--
458-
State: When updating an entity, the audit fields LastModifiedBy and LastModifiedOn are properly updated. When doing a calculation, assert that the result returned is as expected.
459-
Behavior: Verify that a method was (not) called, or called with specific arguments. Example: verify that an email is (not) sent, or that Repository.Save() is called.
460-
-->
461433

462434
---
463435
layout: default-aside
@@ -468,7 +440,7 @@ h1:
468440
position: start
469441
---
470442

471-
# Mocking
443+
# Test Doubles
472444

473445
<v-clicks>
474446

@@ -521,18 +493,18 @@ layout: comparison
521493

522494
### Mockist / Solitary
523495

524-
- 🧐 Mock everything
525-
- ✅ Test complicated BL in isolation
526-
- ⚠️ May be testing implementation instead of behavior
496+
🧐 Mock everything
497+
<br>✅ Test complicated BL in isolation
498+
<br>⚠️ Danger of creating <b>tautological tests</b>, testing implementation instead of behavior
527499

528500
</div>
529501
<div class="col">
530502

531503
### Classicist / Sociable
532504

533-
- 🧐 Mock I/O and/or "awkward" things
534-
- ✅ Tests survive refactorings more easily
535-
- ⚠️ Danger of testing the same thing multiple times
505+
🧐 Mock I/O and/or "awkward" things
506+
<br>✅ Tests survive refactorings more easily
507+
<br>⚠️ Danger of testing the same thing multiple times
536508

537509
</div>
538510
</div>
@@ -544,6 +516,32 @@ Also see: https://martinfowler.com/articles/mocksArentStubs.html
544516
Solitary vs Sociable: https://martinfowler.com/bliki/UnitTest.html
545517
-->
546518

519+
---
520+
layout: code
521+
code-size: 1.1em
522+
---
523+
524+
# Mockist Testing
525+
526+
## When there is no BL
527+
528+
```cs {1-2|4-5|7-8|all}
529+
var repo = Substitute.For<IRepository>();
530+
repo.Get().Returns(["obj1", "obj2"]);
531+
532+
var ctl = new Controller(repo);
533+
var result = ctl.Get();
534+
535+
Assert.That(result[0], Is.EqualTo("obj1"));
536+
Assert.That(result[1], Is.EqualTo("obj2"));
537+
```
538+
539+
<div class="full-width text-3xl text-center mt-8 italic text-orange-400">
540+
⚠️ What are you truly testing here?
541+
</div>
542+
543+
544+
547545
---
548546
layout: two-col-image-text
549547
h1:
@@ -577,17 +575,56 @@ h1:
577575

578576
## It just repeats the code
579577

580-
```cs
581-
var repo = Substitute.For<IRepository>();
582-
repo.Get().Returns(["obj1", "obj2"]);
583-
var ctl = new Controller(repo);
578+
```cs {1|3-4|6|all}
579+
var service = Substitute.For<IService>();
584580

581+
var ctl = new Controller(service);
585582
var result = ctl.Get();
586583

587-
Assert.That(result, Is.Not.Null);
588-
Assert.That(result.Length, Is.EqualTo(2));
584+
service.Received().Get();
589585
```
590586

587+
588+
<div class="full-width text-3xl text-center mt-8 italic text-orange-400">
589+
⚠️ Zero behavior verification <br>
590+
⚠️ Breaks on any change and/or refactoring
591+
</div>
592+
593+
594+
595+
---
596+
layout: default-aside
597+
size: lg
598+
h1:
599+
type: brackets
600+
color: muted
601+
position: all
602+
---
603+
604+
# State vs Behavior
605+
606+
<v-clicks>
607+
608+
- **State Testing**
609+
- Assertion Territory
610+
- Validate that a property has a certain value
611+
- **Behavior Testing**
612+
- Mocking Territory
613+
- Validate that a method was (not) called
614+
615+
</v-clicks>
616+
617+
::image::
618+
619+
![](./images/circle-crown.jpg)
620+
621+
<!--
622+
State: When updating an entity, the audit fields LastModifiedBy and LastModifiedOn are properly updated. When doing a calculation, assert that the result returned is as expected.
623+
Behavior: Verify that a method was (not) called, or called with specific arguments. Example: verify that an email is (not) sent, or that Repository.Save() is called.
624+
-->
625+
626+
627+
591628
---
592629
layout: section
593630
---
@@ -669,21 +706,19 @@ There was also "Record-And-Replay" but no one seems to be using that anymore.
669706

670707
---
671708
layout: code
709+
code-size: 1.09em
672710
---
673711

674712
# AAA in Practice
675713

676-
```ts {1|2-5|7-8|10-11|all}
714+
```ts {1|2-4|6-7|8|all}
677715
test("calculateTotal_multipleItems_returnsSumOfPrices", () => {
678-
// Arrange
679716
const cart = new ShoppingCart()
680717
cart.add({ name: 'Socks', price: 9.99 })
681718
cart.add({ name: 'Shoes', price: 79.99 })
682719

683-
// Act
684720
const total = cart.calculateTotal()
685721

686-
// Assert
687722
expect(total).toBe(89.98)
688723
})
689724
```
@@ -720,6 +755,44 @@ await orderService.placeOrder(order)
720755
expect(emailService.send).toHaveBeenCalledWith(order.customerEmail)
721756
```
722757

758+
---
759+
layout: code
760+
code-size: 0.95em
761+
h1:
762+
type: brackets
763+
color: muted
764+
position: 2
765+
---
766+
767+
# Parameterized Tests
768+
769+
```ts {1-6|8-14|all}
770+
// ✅ Use parameterized: same logic, different inputs
771+
test.each([
772+
{ input: -1, expected: false },
773+
{ input: 0, expected: false },
774+
{ input: 2, expected: true },
775+
{ input: 97, expected: true },
776+
])("isPrime($input) returns $expected", ({ input, expected }) => {
777+
expect(isPrime(input)).toBe(expected)
778+
})
779+
780+
// ❌ Don't parameterize: different scenarios, different intent
781+
// "user with expired token" vs "user with no token"
782+
// → separate tests with descriptive names
783+
```
784+
785+
<div class="mt-4 text-center text-2xl grid">
786+
<div v-click.hide="1" class="text-emerald-400 col-start-1 row-start-1">Boundaries &amp; equivalence classes → <strong>parameterize</strong></div>
787+
<div v-click="[1,2]" class="text-orange-400 col-start-1 row-start-1">Different scenarios or business rules → <strong>separate tests</strong></div>
788+
</div>
789+
790+
<!--
791+
Parameterized tests shine for boundary value analysis and equivalence partitioning — exactly the cases we discussed earlier.
792+
But they obscure intent when scenarios are conceptually different. When a parameterized test fails, the failure message is often just "row 3 failed" — you lose the descriptive test name that tells you WHAT broke.
793+
Rule of thumb: if you can describe all cases with "same function, different numbers" → parameterize. If each case has a different story → separate tests.
794+
-->
795+
723796
---
724797
layout: default
725798
hide: true

0 commit comments

Comments
 (0)