Skip to content

Instantly share code, notes, and snippets.

@practicingruby
Created May 3, 2012 13:53
Show Gist options
  • Save practicingruby/2585793 to your computer and use it in GitHub Desktop.
Save practicingruby/2585793 to your computer and use it in GitHub Desktop.
Questions for drbrain

QUESTION 1: Is there a better way to test that callbacks are being called?

  it "must trigger an event when the danger zone is reached" do
    alert = false

    game.on_event(:enter_region, :danger_zone) { alert = true }
    game.on_event(:leave_region, :danger_zone) { alert = false }

    refute alert, "should not enable alert before danger zone is reached"

    game.move(100,0)
    assert alert, "should endable alert once danger zone is reached"

    game.move(-1, -1)
    refute alert, "should disable alert once danger zone is exited"
  end

QUESTION 2: Is there a better way to test symmetric numerical computations (such as the borders of a rectangle)?

  it "must be able to detect minimum distance from boundaries" do
    map = new_map

    player = new_element("player 1")
    
    # starting at (10,25)
    map.place(player, 10, 25)

    map.nearest_boundary(player).must_equal(5)

    # now at (10, 7)
    map.move(player, 0, -18)
    map.nearest_boundary(player).must_equal(2)

    # now at (10, 91)
    map.move(player, 0, 84)
    map.nearest_boundary(player).must_equal(4)

    # now at (92, 91)
    map.move(player, 82, 0)
    map.nearest_boundary(player).must_equal(3)
  end

QUESTION 3: I was happy with the following acceptance tests, but the support code they rely on is extremely brittle. Should I instead have thought about testing the presenter and not bothering with the full outside-in tests? I could have probably cornered most or all of the bugs I ran into with the untested frontend code that way.

  it "should result in a loss on mine collision" do
    world = Blind::Worlds.original(1)
    levels = [Blind::Level.new(world, "test")]

    game = Blind::UI::GamePresenter.new(levels)

    sim = Blind::UI::Simulator.new(game)

    mine = world.positions.first(:mine)

    sim.move(mine.x, mine.y)

    sim.status.must_equal "You got blasted by a mine! YOU LOSE!"
  end

QUESTION 4: I occasionally have test failures due to floating point errors in distance computations. I would just check that they were within some delta, but the problem is that right now the borders between boundaries in Blind are zero-width. This means the difference between 19.9999999999999999999997 and 20.0 can put something in one region or the other, and the difference between 7.99997 and 8 could cause a mine to explode or not. The former problem can be solved through rejection sampling, the latter is something that does not affect game play because the level of precision does not matter so much. However, because these problems tend to cascade upwards through the tests, I really struggled with them. Any thoughts? (I cheated in some places and just serialized objects that I knew didn't have unexpected rounding issues, but that feels WRONG)

QUESTION 5: How do you test randomization, or do you consider it an implementation detail? I.e. what tests would you write for this feature?

    def self.random(distance_range)
      angle = rand(0..2*Math::PI)
      length = rand(distance_range)

      x = length*Math.cos(angle)
      y = length*Math.sin(angle)

      point = new(x, y)
      center = new(0, 0)

      if distance_range.include?(point.distance(center))
        point
      else
        random(distance_range)
      end
    end

QUESTION 6: Related to the previous question, how do you test code which relies on randomization? Do you generate cached fixtures with predictable results? Write tests that are randomness aware? Make artificial test cases? For example, if you want to test that when a player reaches the exit position, the game ends in a win, how do you make sure that the player doesn't crash into a mine along the way? I ended up creating an artificial scenario with no mines to ensure that the results were deterministic, but it seems to be a cheat. (Similarly, I made a map with one mine to test mine collisions at a specific position)

QUESTION 7: Do you have recommendations for tightening the feedback loop when making major refactors? This is a disaster.

QUESTION 8: Would you write something different here? The use of magic numbers is somewhat innocuous in this case, but makes it so you have to think through the computation in order to understand the test. Does it just need better documentation?

  it "must compute distance between itself and another point" do
    point_a = Blind::Point.new(2, 3)
    point_b = Blind::Point.new(-1, 7)

    point_a.distance(point_b).must_equal(5)
    point_b.distance(point_a).must_equal(5)
  end

QUESTION 9: The magic numbers in this file are a lot worse, because they refer to values buried in a configuration file. From a high level perspective, how would you do this differently?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment