Skip to content

Commit

Permalink
refactor(blog): reorganize articles to focus on distinct topics
Browse files Browse the repository at this point in the history
- Remove redundant content about MUST/SHOULD/MAY levels from older posts
- Streamline 'Rethinking Test Architecture' to focus on separation of concerns
- Update 'From RSpec to Fix' to emphasize syntax and complexity comparison
- Revise 'A Fresh Take on Ruby Testing' to center on minimalist philosophy
- Add new article about RFC 2119 requirement levels

This reorganization ensures each article has a clear, unique focus:
- Fresh Take (2015-09-03): Minimalism and design principles
- RSpec to Fix (2015-09-06): Syntax and complexity comparison
- Test Architecture (2024-12-29): Separation of specifications
- RFC 2119 Levels (2024-12-30): Requirement levels semantics
  • Loading branch information
cyril committed Dec 29, 2024
1 parent 0462f96 commit 82ad289
Show file tree
Hide file tree
Showing 4 changed files with 259 additions and 63 deletions.
75 changes: 27 additions & 48 deletions docs/_posts/2015-09-03-a-fresh-take-on-ruby-testing.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
layout: post
title: "Fix 0.7: A Fresh Take on Ruby Testing"
title: "A Fresh Take on Ruby Testing"
description: "Introducing Fix 0.7, a minimalist Ruby testing framework focused on clear specifications and pure Ruby objects, built in just 148 lines of code."
date: 2015-09-03 12:00:00 +0100
author: Cyril Kato
Expand All @@ -23,7 +23,6 @@ Fix emerged from a simple observation: testing frameworks shouldn't be more comp
### Key Features

- **Pure Specification Documents**: Fix treats specs as living documents that remain logic-free and crystal clear
- **RFC 2119 Compliance**: Requirements are qualified using standardized terminology (MUST, SHOULD, MAY)
- **Version-Resistant**: Specifications remain stable across Fix versions, protecting against software erosion
- **No Magic**: We avoid monkey-patching and other Ruby "[magic tricks](https://blog.arkency.com/2013/06/are-we-abusing-at-exit/)" that can obscure behavior
- **Authentic Ruby Objects**: Work with pure, unmuted Ruby objects for unambiguous and structured specs
Expand Down Expand Up @@ -64,68 +63,48 @@ Surprisingly, RSpec tells us that `App.new` equals 42! While this specific issue

## Fix in Action

Let's see how Fix handles a real-world example. Consider this Duck class:
Let's see how Fix handles a real-world test case:

```ruby
# duck.rb
class Duck
def walks
"Klop klop!"
end

def swims
"Swoosh..."
end

def quacks
puts "Quaaaaaack!"
end
end
```

Here's how we specify its behavior with Fix:

```ruby
# duck_spec.rb
require_relative "duck"
# car_spec.rb
require "fix"

@bird = Duck.new
Fix :Car do
on :new, color: "red" do
it { MUST be_an_instance_of Car }

Fix.describe @bird do
on :swims do
it { MUST eql "Swoosh..." }
end

on :speaks do
it { MUST raise_exception NoMethodError }
end
on :color do
it { MUST eql "red" }
end

on :sings do
it { MAY eql "♪... ♫..." }
on :start do
it { MUST change(car, :running?).from(false).to(true) }
end
end
end
```

Running the specification:

```bash
$ ruby duck_spec.rb
..I

1. Info: undefined method `sings' for #<Duck:0x007fb60383b740> (NoMethodError).
Ran 3 tests in 0.00038 seconds
100% compliant - 1 infos, 0 failures, 0 errors
# Running the specification
Fix[:Car].test { Car }
```

Notice how Fix provides clear, unambiguous results while maintaining a simple and elegant syntax.
Notice how Fix:
- Keeps specifications clear and concise
- Uses method chaining for natural readability
- Focuses on behavior rather than implementation details
- Maintains consistent syntax across different types of tests

## Looking Forward

As we approach version 1.0.0, our focus remains on stability and refinement rather than adding new features. Fix is ready for production use, and we're excited to see how the Ruby community puts it to work.

### Get Involved
### Key Areas of Focus

1. **Documentation Enhancement**: Making it easier for newcomers to get started
2. **Performance Optimization**: Ensuring Fix remains lightweight and fast
3. **Community Feedback**: Incorporating real-world usage patterns
4. **Ecosystem Growth**: Building tools and extensions around the core framework

## Get Involved

- Try Fix in your projects: `gem install fix`
- [Visit our GitHub repository](https://github.com/fixrb/fix)
Expand Down
50 changes: 41 additions & 9 deletions docs/_posts/2015-09-06-from-rspec-to-fix.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ One of the most striking differences between Fix and traditional testing framewo

The core philosophy is simple: a testing framework shouldn't be more complex than the code it tests. This dramatic difference in code size (16,619 lines of code) reflects Fix's commitment to minimalism and clarity.

## Comparing Approaches: A Real-World Example
## A Real-World Comparison

Let's examine how both frameworks handle a real-world testing scenario. Consider this Monster class:
Let's look at a real-world example that demonstrates the key differences in approach. Consider this Monster class:

```ruby
class Monster
Expand All @@ -66,7 +66,7 @@ class Monster
end
```

### Traditional RSpec Approach
### RSpec's Layered Approach

```ruby
require_relative "monster"
Expand Down Expand Up @@ -101,7 +101,7 @@ RSpec.describe Monster do
end
```

### The Fix Way
### Fix's Direct Style

```ruby
require_relative "monster"
Expand All @@ -126,18 +126,50 @@ Fix.describe Monster do
end
```

As we can see, the spec is shorter and easier to read, with a "DRY" approach. Fix allows describing methods with one expression, whether it concerns a class method's name or an instance method's name.
## Key Differentiators

Additionally, all specifications are derived from the described front object that is populated at the root. Unlike in RSpec, there is no concept of implicit or explicit subjects - there is just one read-only dynamic subject which is deduced from the front object and the described methods.
1. **Method Chaining**: Fix allows describing methods with one expression, whether for class or instance methods. This leads to more concise and readable code.

Finally, while an RSpec expectation sometimes needs a parameter to handle [equivalence matcher](http://www.rubydoc.info/github/rspec/rspec-expectations/RSpec%2FMatchers%3Aeql), sometimes a block to handle [expect error matcher](http://www.rubydoc.info/github/rspec/rspec-expectations/RSpec%2FMatchers%3Araise_error), Fix's expectations are always written the same way, regardless of the responsibility and structure of matchers.
2. **Single Source of Truth**: All specifications are derived from the described front object populated at the root. There's no need for explicit or implicit subjects - there's just one read-only dynamic subject deduced from the front object and described methods.

This article has presented some key differences in syntax between these two frameworks. I hope you will enjoy the new test interface proposed by Fix.
3. **Consistent Syntax**: Fix maintains the same syntax regardless of what's being tested. Whether you're checking a value, expecting an error, or verifying a state change, the syntax remains uniform and predictable.

## Clarity in Practice

Fix encourages a more direct and less ceremonial approach to testing. Compare how both frameworks handle error checking:

RSpec:
```ruby
expect { problematic_call }.to raise_exception(ErrorType)
```

Fix:
```ruby
it { MUST raise_exception ErrorType }
```

Or value comparison:

RSpec:
```ruby
expect(value).to eq(expected)
```

Fix:
```ruby
it { MUST eql expected }
```

This consistency helps reduce cognitive load and makes tests easier to write and understand.

## Conclusion

Fix represents a fresh approach to Ruby testing that prioritizes simplicity and clarity. By reducing complexity and maintaining a consistent syntax, it helps developers focus on what matters: writing clear, maintainable tests that effectively verify their code's behavior.

Want to try Fix for yourself? Get started with:

```sh
gem install fix
```

Visit our [documentation](https://fixrb.dev) to learn more about how Fix can improve your testing workflow.
Visit our [documentation](https://rubydoc.info/gems/fix) to learn more about how Fix can improve your testing workflow.
23 changes: 17 additions & 6 deletions docs/_posts/2024-12-29-rethinking-test-architecture-with-fix.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,7 @@ This separation brings several major advantages:

Specifications become autonomous documents that can be reused across different implementations. The same calculator specification could be used to test different calculator classes as long as they follow the same interface.

### 2. Clear Intentions

Fix specifications express requirements using semantic language inspired by RFC 2119 (MUST, SHOULD, MAY). This approach makes specifications more precise and more understandable.

### 3. Isolated Testing
### 2. Isolated Testing

Each test can be executed in complete isolation, which makes debugging easier and improves test code maintainability. The separation between specification and implementation means you can change how you test without changing what you're testing.

Expand Down Expand Up @@ -112,7 +108,22 @@ Fix[:PaymentSystem].test { StripePayment.new(amount: 100) }
Fix[:PaymentSystem].test { PaypalPayment.new(amount: 100) }
```

In this example, the payment system specification is generic and can be applied to different payment implementations.
In this example, the payment system specification is generic and can be applied to different payment implementations. By focusing on the interface rather than the implementation details, we create a reusable contract that any payment processor can fulfill.

## Benefits in Practice

This architectural separation provides several practical benefits:

1. **Documentation**: Specifications serve as clear, living documentation of your system's expected behavior

2. **Maintainability**: Changes to test implementation don't require changes to specifications

3. **Flexibility**: The same specifications can verify multiple implementations, making it ideal for:
- Testing different versions of a class
- Verifying third-party integrations
- Ensuring consistency across microservices

4. **Clarity**: By separating what from how, both specifications and tests become more focused and easier to understand

## Conclusion

Expand Down
Loading

0 comments on commit 82ad289

Please sign in to comment.