mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-07-18 20:59:39 +02:00
* add kind to transaction model * Basic transfer creator * Fix method naming conflict * Creator form pattern * Remove stale methods * Tweak migration * Remove BaseQuery, write entire query in each class for clarity * Query optimizations * Remove unused exchange rate query lines * Remove temporary cache-warming strategy * Fix test * Update transaction search * Decouple transactions endpoint from IncomeStatement * Clean up transactions controller * Update cursor rules * Cleanup comments, logic in search * Fix totals logic on transactions view * Fix pagination * Optimize search totals query * Default to last 30 days on transactions page if no filters * Decouple transactions list from transfer details * Revert transfer route * Migration reset * Bundle update * Fix matching logic, tests * Remove unused code
87 lines
3.3 KiB
Text
87 lines
3.3 KiB
Text
---
|
|
description:
|
|
globs: test/**
|
|
alwaysApply: false
|
|
---
|
|
Use this rule to learn how to write tests for the Maybe codebase.
|
|
|
|
Due to the open-source nature of this project, we have chosen Minitest + Fixtures for testing to maximize familiarity and predictability.
|
|
|
|
- **General testing rules**
|
|
- Always use Minitest and fixtures for testing, NEVER rspec or factories
|
|
- Keep fixtures to a minimum. Most models should have 2-3 fixtures maximum that represent the "base cases" for that model. "Edge cases" should be created on the fly, within the context of the test which it is needed.
|
|
- For tests that require a large number of fixture records to be created, use Rails helpers to help create the records needed for the test, then inline the creation. For example, [entries_test_helper.rb](mdc:test/support/entries_test_helper.rb) provides helpers to easily do this.
|
|
|
|
- **Write minimal, effective tests**
|
|
- Use system tests sparingly as they increase the time to complete the test suite
|
|
- Only write tests for critical and important code paths
|
|
- Write tests as you go, when required
|
|
- Take a practical approach to testing. Tests are effective when their presence _significantly increases confidence in the codebase_.
|
|
|
|
Below are examples of necessary vs. unnecessary tests:
|
|
|
|
```rb
|
|
# GOOD!!
|
|
# Necessary test - in this case, we're testing critical domain business logic
|
|
test "syncs balances" do
|
|
Holding::Syncer.any_instance.expects(:sync_holdings).returns([]).once
|
|
|
|
@account.expects(:start_date).returns(2.days.ago.to_date)
|
|
|
|
Balance::ForwardCalculator.any_instance.expects(:calculate).returns(
|
|
[
|
|
Balance.new(date: 1.day.ago.to_date, balance: 1000, cash_balance: 1000, currency: "USD"),
|
|
Balance.new(date: Date.current, balance: 1000, cash_balance: 1000, currency: "USD")
|
|
]
|
|
)
|
|
|
|
assert_difference "@account.balances.count", 2 do
|
|
Balance::Syncer.new(@account, strategy: :forward).sync_balances
|
|
end
|
|
end
|
|
|
|
# BAD!!
|
|
# Unnecessary test - in this case, this is simply testing ActiveRecord's functionality
|
|
test "saves balance" do
|
|
balance_record = Balance.new(balance: 100, currency: "USD")
|
|
|
|
assert balance_record.save
|
|
end
|
|
```
|
|
|
|
- **Test boundaries correctly**
|
|
- Distinguish between commands and query methods. Test output of query methods; test that commands were called with the correct params. See an example below:
|
|
|
|
```rb
|
|
class ExampleClass
|
|
def do_something
|
|
result = 2 + 2
|
|
|
|
CustomEventProcessor.process_result(result)
|
|
|
|
result
|
|
end
|
|
end
|
|
|
|
class ExampleClass < ActiveSupport::TestCase
|
|
test "boundaries are tested correctly" do
|
|
result = ExampleClass.new.do_something
|
|
|
|
# GOOD - we're only testing that the command was received, not internal implementation details
|
|
# The actual tests for CustomEventProcessor belong in a different test suite!
|
|
CustomEventProcessor.expects(:process_result).with(4).once
|
|
|
|
# GOOD - we're testing the implementation of ExampleClass inside its own test suite
|
|
assert_equal 4, result
|
|
end
|
|
end
|
|
```
|
|
|
|
- Never test the implementation details of one class in another classes test suite
|
|
|
|
- **Stubs and mocks**
|
|
- Use `mocha` gem
|
|
- Always prefer `OpenStruct` when creating mock instances, or in complex cases, a mock class
|
|
- Only mock what's necessary. If you're not testing return values, don't mock a return value.
|
|
|
|
|