From b2311bcd7587a07d4671eb6271f7961837d404b8 Mon Sep 17 00:00:00 2001 From: Elena Tanasoiu Date: Fri, 13 Dec 2024 16:50:22 +0000 Subject: [PATCH] Make the change backwards-compatible This supports both the old version (single value) and new version (hash-based). I've added back the tests from the old version to check that the code stills works when we provide a single value. I've also adapted the README a bit to explain both versions. --- README.md | 24 +++++++++++++++++++++--- lib/scientist/observation.rb | 5 ++++- test/scientist/experiment_test.rb | 30 ++++++++++++++++++++++++++++-- 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 1914cd9..e01e8ec 100644 --- a/README.md +++ b/README.md @@ -121,7 +121,7 @@ class MyWidget e.try { UserService.slug_from_login login } # returns String instance or ArgumentError compare_error_message_and_class = -> (control, candidate) do - control.class == candidate.class && + control.class == candidate.class && control.message == candidate.message end @@ -129,7 +129,7 @@ class MyWidget control.class == ArgumentError && candidate.class == ArgumentError && control.message.start_with?("Input has invalid characters") && - candidate.message.start_with?("Invalid characters in input") + candidate.message.start_with?("Invalid characters in input") end e.compare_errors do |control, candidate| @@ -550,7 +550,25 @@ end #### Providing fake timing data -If you're writing tests that depend on specific timing values, you can provide canned durations using the `fabricate_durations_for_testing_purposes` method, and Scientist will report these in `Scientist::Observation#duration` and `Scientist::Observation#cpu_time` instead of the actual execution times. +If you're writing tests that depend on specific timing values, you can provide canned durations using the `fabricate_durations_for_testing_purposes` method. This can be done using either the old version (single value) or the new version (hash-based) to include both duration and cpu_time. + +##### Old version (Single Value) + +In the old version, you can provide a single value for the duration: + +```ruby +science "absolutely-nothing-suspicious-happening-here" do |e| + e.use { ... } # "control" + e.try { ... } # "candidate" + e.fabricate_durations_for_testing_purposes( "control" => 1.0, "candidate" => 0.5 ) +end +``` + +`fabricate_durations_for_testing_purposes` takes a Hash of duration values, keyed by behavior names. (By default, Scientist uses `"control"` and `"candidate"`, but if you override these as shown in [Trying more than one thing](#trying-more-than-one-thing) or [No control, just candidates](#no-control-just-candidates), use matching names here.) If a name is not provided, the actual execution time will be reported instead. + +##### New version (Hash-based) + +Scientist will report these in `Scientist::Observation#duration` and `Scientist::Observation#cpu_time` instead of the actual execution times. ```ruby science "absolutely-nothing-suspicious-happening-here" do |e| diff --git a/lib/scientist/observation.rb b/lib/scientist/observation.rb index df948e0..2b13903 100644 --- a/lib/scientist/observation.rb +++ b/lib/scientist/observation.rb @@ -35,9 +35,12 @@ def initialize(name, experiment, fabricated_duration: nil, &block) @exception = e end - if fabricated_duration + if fabricated_duration.is_a?(Hash) @duration = fabricated_duration["duration"] @cpu_time = fabricated_duration["cpu_time"] + elsif fabricated_duration + @duration = fabricated_duration + @cpu_time = 0.0 # setting a default value else end_wall_time, end_cpu_time = capture_times @duration = end_wall_time - start_wall_time diff --git a/test/scientist/experiment_test.rb b/test/scientist/experiment_test.rb index e9468e7..434e673 100644 --- a/test/scientist/experiment_test.rb +++ b/test/scientist/experiment_test.rb @@ -671,7 +671,20 @@ def @ex.enabled? end describe "testing hooks for extending code" do - it "allows a user to provide fabricated durations for testing purposes" do + it "allows a user to provide fabricated durations for testing purposes (old version)" do + @ex.use { true } + @ex.try { true } + @ex.fabricate_durations_for_testing_purposes( "control" => 0.5, "candidate" => 1.0 ) + + @ex.run + + cont = @ex.published_result.control + cand = @ex.published_result.candidates.first + assert_in_delta 0.5, cont.duration, 0.01 + assert_in_delta 1.0, cand.duration, 0.01 + end + + it "allows a user to provide fabricated durations for testing purposes (new version)" do @ex.use { true } @ex.try { true } @ex.fabricate_durations_for_testing_purposes({ @@ -692,7 +705,20 @@ def @ex.enabled? assert_equal 0.9, cand.cpu_time end - it "returns actual durations if fabricated ones are omitted for some blocks" do + it "returns actual durations if fabricated ones are omitted for some blocks (old version)" do + @ex.use { true } + @ex.try { sleep 0.1; true } + @ex.fabricate_durations_for_testing_purposes( "control" => 0.5 ) + + @ex.run + + cont = @ex.published_result.control + cand = @ex.published_result.candidates.first + assert_in_delta 0.5, cont.duration, 0.01 + assert_in_delta 0.1, cand.duration, 0.01 + end + + it "returns actual durations if fabricated ones are omitted for some blocks (new version)" do @ex.use { true } @ex.try do start_time = Time.now