1
0
Fork 0
mirror of https://github.com/maybe-finance/maybe.git synced 2025-07-18 20:59:39 +02:00
Maybe/.cursor/rules/testing.mdc
Zach Gollwitzer 1aae00f586
perf(transactions): add kind to Transaction model and remove expensive Transfer joins in aggregations (#2388)
* 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
2025-06-20 13:31:58 -04:00

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.