EMZETT.
Login

Kurz: Ruby bringt Minitest mit; RSpec ist die beliebte Alternative. Ein Test ist eine Klasse mit Methoden, die mit test_ beginnen:

Teil des Kurses Ruby

Kapitel 10 von 12 im Kurs Ruby (Abschnitt „Werkzeuge“). Mit Fortschritt, Quiz und Zertifikat auf der Lernseite.

Tests mit Minitest

Ruby bringt Minitest mit; RSpec ist die beliebte Alternative. Ein Test ist eine Klasse mit Methoden, die mit test_ beginnen:

require "minitest/autorun"
 
class Rechner
  def addiere(a, b) = a + b
  def teile(a, b)
    raise ZeroDivisionError, "durch null" if b.zero?
    a / b
  end
end
 
class RechnerTest < Minitest::Test
  def setup
    @r = Rechner.new
  end
 
  def test_addition
    assert_equal 5, @r.addiere(2, 3)
  end
 
  def test_teilen
    assert_in_delta 2.5, @r.teile(5, 2.0), 0.001
  end
 
  def test_fehler
    assert_raises(ZeroDivisionError) { @r.teile(1, 0) }
  end
 
  def test_enthaelt
    assert_includes [1, 2, 3], 2
    refute_nil @r
  end
end
Run options: --seed 12345
 
# Running:
 
....
 
Finished in 0.001s, 4000.0 runs/s, 6000.0 assertions/s.
 
4 runs, 6 assertions, 0 failures, 0 errors, 0 skips

Seed und Zeitangaben ändern sich bei jedem Lauf; wichtig ist die letzte Zeile mit der Zusammenfassung. Typische Assertions: assert, assert_equal, assert_nil, assert_raises, assert_includes, assert_in_delta, assert_match; Gegenstücke mit refute_.

RSpec liest sich wie eine Beschreibung:

RSpec.describe Rechner do
  subject(:rechner) { described_class.new }
 
  describe "#addiere" do
    it "addiert zwei Zahlen" do
      expect(rechner.addiere(2, 3)).to eq(5)
    end
  end
 
  describe "#teile" do
    it "wirft bei Division durch null" do
      expect { rechner.teile(1, 0) }.to raise_error(ZeroDivisionError)
    end
  end
end

Starten: rspec bzw. ruby test/rechner_test.rb.

Gems und Bundler

Pakete heißen Gems (rubygems.org). Bundler verwaltet sie projektweit:

gem install colorize          # global installieren
gem list                      # installierte Gems
bundle init                   # Gemfile erzeugen
bundle add rack               # Gem hinzufügen
bundle install                # alle Gems installieren
bundle exec ruby app.rb       # mit den Versionen aus Gemfile.lock starten

Die Gemfile:

source "https://rubygems.org"
 
ruby "3.3.6"
 
gem "sinatra", "~> 4.0"
gem "sequel"
 
group :test do
  gem "minitest"
  gem "rack-test"
end

~> 4.0 bedeutet “ab 4.0, aber unter 5.0”. Die Datei Gemfile.lock hält exakte Versionen fest und gehört ins Repository.

Ein eigenes Gem / Projekt strukturieren

mein_projekt/
├── Gemfile
├── lib/
│   ├── mein_projekt.rb
│   └── mein_projekt/rechner.rb
├── test/
│   └── rechner_test.rb
├── Rakefile
└── bin/mein_programm
# lib/mein_projekt.rb
require_relative "mein_projekt/rechner"
 
module MeinProjekt
  VERSION = "0.1.0"
end

require_relative lädt Dateien relativ zur aktuellen Datei, require sucht im Ladepfad. Rake (Rakefile) ist Rubys Build-Werkzeug:

task default: :test
 
desc "Tests ausführen"
task :test do
  ruby "test/rechner_test.rb"
end

Qualität

  • RuboCop: Stilprüfung und Autokorrektur (rubocop -A)
  • Sorbet / RBS / Steep: optionale Typisierung
  • YARD: Dokumentation aus Kommentaren
  • Debugger: binding.irb oder debug im Code, byebug/pry als Alternativen
# Minimaler Selbsttest ohne Framework
def pruefe(name)
  ergebnis = yield
  puts "#{ergebnis ? 'OK  ' : 'FAIL'} #{name}"
rescue => e
  puts "FAIL #{name}: #{e.class}"
end
 
pruefe("Summe") { [1, 2, 3].sum == 6 }
pruefe("Reverse") { "abc".reverse == "cba" }
pruefe("Absichtlich falsch") { 1 + 1 == 3 }
pruefe("Fehler") { Integer("x") }

Ausgabe:

OK   Summe
OK   Reverse
FAIL Absichtlich falsch
FAIL Fehler: ArgumentError

Merke

  • Minitest (eingebaut) und RSpec für Tests; assert_equal, assert_raises
  • Gems von rubygems.org, Bundler (Gemfile, Gemfile.lock, bundle exec)
  • Projektstruktur: lib/, test/, Rakefile
  • RuboCop für Stil, binding.irb zum Debuggen

Übungsaufgabe

Schreibe eine Klasse Stapel mit push, pop, leer? und drei Tests mit Minitest.

Quiz zur Selbstkontrolle

Weiter im Kurs

Zurück: Metaprogrammierung und Ruby-Idiome

Weiter: Web, Rails und Ökosystem

Alle Kapitel: Ruby im Überblick