Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Writing Minitest clone in 30 minutes

Writing Minitest clone in 30 minutes

Masafumi Okura

December 16, 2023
Tweet

More Decks by Masafumi Okura

Other Decks in Programming

Transcript

  1. Features of Minitest • Just Ruby • No DSL •

    Fast • Supports spec style testing • describe, it, etc. • Clean and readable
  2. Features of Minitest • Just Ruby • No DSL •

    Fast • Supports spec style testing • describe, it, etc. • Clean and readable
  3. Me • Name: OKURA Masafumi (େ૔խ࢙) • From: Tokyo, Japan

    • Work: Freelance web developer (Rails) • Activities: Kaigi on Rails, Alba, etc. • Hobbies: Coffee, learning languages including Chinese • Development environment: Neovim, iTerm2, zsh
  4. What Minitest does • `ruby sample_test.rb` evaluates test fi le

    • Instance methods including `setup` are de fi ned, no class methods are de fi ned • All instance methods whose name start with `test_` are recognized as test methods • Inside test methods there are assertion methods • When assertion methods are executed it stores results, and when the result is failure the execution stops • It produces some outputs like "2 runs, 3 assertions, 0 failures"
  5. Problems • There's no explicit step to execute tests •

    There's no explicit step to create an instance of the test class • Not all methods are test methods • Tests whose name do not start with `test_` are simply helper methods • It needs to collection results
  6. Solutions • We can use `at_exit` hook to execute test

    • Alternatively, we can use `ObjectSpace` module to get all classes with `Test` suf fi x, but this is much more complicated • Inside `at_exit` hook we can create an instance of the test class • We can use `method_added` hook to check the name and if it matches `test_` pre fi x it's marked as a test method. • We can store results in an instance variable
  7. at_exit • Executed when Ruby interpreter exits • Not suitable

    for a large business logic, but convenient for smaller tasks • https://docs.ruby-lang.org/en/master/Kernel.html#method-i-at_exit
  8. some_class.class_eval(&block) • Executes given block as if it’s in the

    class • The argument can be a String instead of a block, but block form is often preferred • Useful if we want to do a lot of thing for that class • https://docs.ruby-lang.org/en/master/Module.html#method-i- class_eval
  9. def self.inherited(subclass) • Can be used when subclass needs some

    behavior • `subclass` argument is a `Class` object, so we can call `class_eval`, `include` or `extend` on it • Don’t forget to call `super` • https://docs.ruby-lang.org/en/master/Class.html#method-i- inherited
  10. def self.method_added(name) • Lesser known, less frequently used • Can

    be used when we want to categorize methods, treat some methods as special ones, and customize each method • When customize, it’s often used with `method` and `de fi ne_method` method • https://docs.ruby-lang.org/en/master/Module.html#method-i- method_added
  11. Designing a framework/library • Be familiar with the features the

    language gives us • In Ruby, there are varieties of hooks • Think of usages, rather than implementations • Autorun is a optional but useful feature, so we want it • Consider where to put what data • In more complex case, more data would be stored in its own place