0

Suppose we want to make steaks.

Public class Restaurant{
    public void MakeSteak(Steak rawSteak) {
      this.KitchenServices.AddSeasoning(rawSteak);
      this.KitchenServices.Grill(rawSteak);
    }
}

In the unit tests, I could make sure that given a raw steak, we both season it and grill it:

public void MakeSteakTest() {
  var rawSteak = new Steak();
  this.restaurant.MakeSteak(rawSteak);
  this.KitchenServices.Verify(x => x.AddSeasoning(rawSteak) , Times.Once);
  this.KitchenServices.Verify(x => x.Grill(rawSteak) , Times.Once);
}

My question is that should we have a test to make sure that the steak is not seasoned after it's grilled? If yes, How?

havij
  • 1,030
  • 14
  • 29
  • 1
    Possible duplicate of [How to test method call order with Moq](https://stackoverflow.com/questions/1765738/how-to-test-method-call-order-with-moq) – Dirk Herrmann Mar 05 '19 at 17:31

3 Answers3

4

Generally you should test results, not implementation in a unit test. What happens in your system if MakeSteak were changed so that the operations were in a different order? Is that something that is observable? Since your only intput is a Steak object, is there some sort of validation that fails if Grill is called before AddSeasoning? That is what you should be testing.

D Stanley
  • 149,601
  • 11
  • 178
  • 240
  • I agree that we should usually avoid testing implementation details, but what if there are some business logic that enforces that we always should season the steak before we grill it, how can I make sure this premise is not broken in future changes? – havij Mar 05 '19 at 17:28
  • Again, what _happens_ if you call the methods in a different order? Does something change in the state of the system? Is an exception thrown? If nothing changes, then why does it matter what order they're called in? – D Stanley Mar 05 '19 at 17:30
1

One way would be to represent each operation as a command object which operates on the steak e.g.

interface ISteakOp {
    void DoTo(Steak s);
}

class AddSeasoningOp : ISteakOp { ... }
class GrillOp : ISteakOp { ... }

then return a sequence of operations:

public List<ISteakOp> MakeSteakOps() {
    return new List<ISteakOp> {
        new AddSeasoningOp(),
        new GrillOp()
    };
}

then your test can assert that any grill op occurs before any seasoning:

var ops = MakeSteakOps();
var grillIndex = ops.IndexOf(o => o is GrillOp);
if (grillIndex != -1) {
    var seasonIndex = ops.IndexOf(o = o is AddSeasoningOp);
    Assert.That(seasonIndex == -1 || seasonIndex < grillIndex);
}
Lee
  • 142,018
  • 20
  • 234
  • 287
1

My question is that should we have a test to make sure that the steak is not seasoned after it's grilled?

First: Does it have an effect on behavior that is visible to the End User/Stakeholder, and do they care?

If yes, How?

Then:

  • How is it that the is able to detect that effect on behavior? Use that same method in your test.
  • What's the behavior that the user is expecting? Use that expectation in your test.

This might sound "too straightforward"/"dismissively simple", but I'm totally serious. That is the definition of proper behavioral testing.

Kache
  • 15,647
  • 12
  • 51
  • 79