# social-unit-tests

## Social Tests

### What

* Also known as
  * documentation tests
  * acceptance unit tests
  * module tests
* test that verifies the behavior of a unit (e.g., a class or a function) in collaboration with its real dependencies rather than mocking them
  * Any infrastructure calls (ie http, message bus, files etc) are stubbed/faked out
* Writing tests without using mocks/spies, but using stubbed out (test implementation of dependencies with possible extra logic or static factories in prod code used only for test), to test several classes at a time.
* Used in testing the core of hexagonal architecture
  * With business rules being tested
  * with the ports implementing fakes
  * Adapters not tested
* Avoiding use of mocks to verify
  * as these are dealt with ....????
  *
* Care about the output
  * ie the reponse
* This is a testing pattern, and not a hammer
  * should be have reasons to use, and use other tests type

### Characteristics

* Real Collaborators: The unit interacts with its actual dependencies.
* Integration-Like: Tests a small part of the system, often a subset of the domain or application logic, an aggregate
* Behavior-Oriented: Focuses on the outcome of the collaboration rather than internal implementation details.
* Limited Scope: While broader than solitary tests, they do not span the entire application stack (e.g., they exclude the database or external systems).

## Advantages

* Thus allowing ease of refactoring, as code is not tied test implementation.
* validate the actual collaboration between multiple units, rather than have fine grained tests
* When testing the business logic in a domain-driven design or hexagonal architecture, sociable tests ensure domain entities and value objects work together correctly.
  * Example: An aggregate root interacting with child entities to enforce invariants.
* Good for handling complex interactions.
  * When interactions between multiple components are too complex to mock effectively without missing edge cases or creating brittle tests.
  * Example: Validating the flow of a process where components communicate heavily (e.g., an order placement pipeline).
* Avoiding Mocking Overhead:
  * Sociable tests are beneficial when mocking dependencies would introduce unnecessary complexity or make the test fragile.
  * Example: A calculator service that depends on multiple reusable utility classes.
* Avoid testing implementation, and focus on testing behaviour
* Focused on business rules:
  * avoid testing situations that will never happen in a business flow,
  * example: as the calling object calling it might never have the state that could be used in the test.
  * Can be used with BDD language and be read by business
* Avoid mocking/stubbing business rules that might return the wrong thing
* Less end to end acceptance tests

### Disadvantages/When not to use

* Testing Behavior with External Systems or boundaries:
  * Avoid sociable tests for interactions with databases, file systems, network APIs, or other external systems.
  * This is integration tests
* Highly Independent Units:
  * If a unit has minimal or no interaction with other components, a solitary unit test is sufficient.
    * Example: Testing a string utility function or a pure algorithm.
* Complex algorithms/rules:
  * Can start off with a social test, but might be easier to unit test the rules/algorithm separately and easier (ie remove dependency graph)
* Non-Deterministic Behavior:
  * unsuitable for systems with non-deterministic behavior (e.g., random number generation, time-based behavior) unless the randomness can be controlled.
  * Example: A test that depends on real-world timing or randomness.
* Complex Dependency Graphs
  * hen the dependency graph is too complex, as this can lead to brittle and slow tests.
  * Example: A service relying on many indirect dependencies through deeply nested calls.
  * This can be handled via a factory
* Performance Concerns:
  * Can be slow due to complex setups or large numbers of interacting components, they may not be ideal for fast feedback loops.
* Can be harder to isolate failures
  * When multiple units are involved, it can be difficult to pinpoint which unit is causing a test failure.
  * Will need to use a debugger more
* Limited Fault Injection
  * It’s harder to simulate specific edge cases or failure scenarios compared to solitary tests with mocks or stubs.
  * Example: Testing how a service handles an exception from a dependency may require significant effort to trigger that failure
* Overlap with Integration Tests
  * may duplicate the purpose of integration tests, leading to redundancy and wasted effort.
* Reduced Control Over Dependencies
  * use real dependencies, which means they lack the fine-grained control provided by mocks or fakes.
  * A dependency that randomly changes its state (e.g., based on system time) might cause sporadic test failures.
  * Real dependencies may introduce non-determinism (e.g., caching, threading, random inputs), making tests unreliable.
* Potential Over-Reliance
  * Overusing sociable tests can lead to insufficient solitary unit tests, which are crucial for pinpointing issues within individual units.
  *

### Examples

### Links

* https://www.jamesshore.com/v2/projects/testing-without-mocks/testing-without-mocks
