BDD Question: Low Level Behavior And Wrapper Methods?

I have a service object with an interface explicitly defined for it. I like this because it let’s me unit test the things that need the service without having to worry about the implementation detail of the actual service.

public interface IMyService
{
  public void DoSomething();
  public void AnotherThingHere();
}

When I get to the implementation of this service and I start specifying the behavior through my specification/tests, I create a class that has a dependency on another interface – ISomeRepository. This repository is used in both methods of the actual service implementation.

For the “AnotherThingHere” method, I end up with several specification/tests because that method has some good business logic in it.

For the “DoSomething” method, though, the real implementation is only a pass-through to the repository and my specification/test ends up looking like this:

[TestFixture]
public class When_doing_something: ContextSpecification
{
 
 ISomeRepository repo;
 
 public override void Context()
 {
   repo = MockRepository.GenerateMock<ISomeRepository>();
   IMyService myService = new MyService(repo);
 
   myService.DoSomething();
 }
 
 [Test]
 public void Should_do_something()
 {
   repo.AssertWasCalled(r => r.DoSomething());
 }
 
}

I know this specification is necessary because I am using the “DoSomething” method of IMyService in other parts of the system. I think there is value in having an IMyService interface explicitly because it simplified the specification/tests for the parts of the system that need to use it, and decoupled the system to a point that made it much easier to code and change.

So my question is, do you see any real value in a specification/test name like “When doing something, should do something”? or should I be looking at this test from a different “style” or perspective?

I think this specification/test is valuable, but I also think the test name and observation name are silly since they say the same thing. Advice? Different naming suggestions? What am I missing or just not seeing? or is this ok and I’m just running on 25% brain power due to lack of sleep today?


Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Derick Bailey

Derick Bailey is an entrepreneur, problem solver (and creator? :P ), software developer, screecaster, writer, blogger, speaker and technology leader in central Texas (north of Austin). He runs SignalLeaf.com - the amazingly awesome podcast audio hosting service that everyone should be using, and WatchMeCode.net where he throws down the JavaScript gauntlets to get you up to speed. He has been a professional software developer since the late 90's, and has been writing code since the late 80's. Find me on twitter: @derickbailey, @mutedsolutions, @backbonejsclass Find me on the web: SignalLeaf, WatchMeCode, Kendo UI blog, MarionetteJS, My Github profile, On Google+.
This entry was posted in .NET, Behavior Driven Development, C#, Unit Testing. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://www.edgewolf.com/edus Nolan Egly

    I agree that repeating the name is silly, but can’t comment too intelligently without seeing the DoSomething implementation.

    When..then…should…etc. is not to be followed dogmatically. It’s a guide to make the names more readable.

    Change the test fixture name, or change the name of the test. I’ve started using “While…” or “With…” for test fixture names to add more general context when appropriate.

  • Matt Hinze

    Ok, here’s my take.

    Repository is a first class concept and can be used to compose behavior. The following sounds fine:

    “When performing an operation on the floogles, should retrieve the floogles from the repository.”

    However, pass through methods like that which do nothing else are silly, and that’s why they have silly sounding context descriptions and specifications.

  • http://www.lostechies.com/members/derick.bailey/default.aspx derick.bailey

    @nolan,

    the implementation of DoSomething is this:

    public void DoSomething()
    {
    someRepo.DoSomething();
    }

    @matt,
    maybe i shouldn’t have picked “repository” for the example. it doesn’t matter if it’s a repository or not. it’s a dependency that ends up being passed through one-to-one for the method call in this case.

  • Matt Hinze

    Yeah, I know. I’m questioning the need for that pass-through method at all, and I think your discomfort with the spec should lead you to ask the same question..

  • http://www.kevinwilliampang.com Kevin Pang

    @Matt Hinze

    What’s the alternative? The service layer is obviously there because certain operations need to be centralized. He could call the repository directly, but that probably breaks some encapsulation rules he has in place and possibly introduces unnecessary dependencies into his project (e.g. now he needs to reference the repository project as well as the service project).

    @Derick Bailey

    I agree that there is value in having the IMyService interface to facilitate testing, but is there really a point in testing the DoSomething function if it’s simply a pass-through to the repository? It’s admirable to strive for 100% test coverage, but to me it seems like a waste of time until you actually have some business logic to test out.

  • Matt Hinze

    The alternative is to take a dependency on IMyRepository and IMyService.. they are both first-class domain concepts and should be in the same project. We put them in “Core” … He doesn’t need to reference the repository _implementation_ – all that NHibernate stuff would live in a data access project. He’s implicitly dependent on the IMyRepository anyway.

    And yes, if he keeps it, he should test the interaction.

  • http://www.lostechies.com/members/derick.bailey/default.aspx derick.bailey

    @kevin – i see value in testing that pass through. what happens if someone deletes that line of code by accident? or changes it to do something else? without a test around it, we would not know something is wrong.

    @matt – my theory has been to try and avoid passing the same dependency into multiple objects in the same graph… i should only need one instance of the dependency in the graph.

    this theory may be dumb, though. when you examine the object graph at design time, there is only one instance of the dependency because we’re using interfaces. it’s only at run time that the dependency is multiplied in the graph.

    it’s certainly worth considering… i’m hesitant to do that, though.

  • Matt Hinze

    Derick, *I* haven’t considered *that*.. can you elaborate? Maybe a separate post is in order, I’d like to see you go 5 whys deep on it.

  • http://www.lostechies.com/members/scottcreynolds/default.aspx Scott C Reynolds

    I assume there’s a consumer of IMyservice, and that it has a reason to do something. Then your test becomes

    when_some_context_that_requires_IMyservice

    it_should_yield_some_expected_result_because_it_called_dosomething.

    obviously those aren’t the names, but you get the gist. IMyService has a reason for existing, and it is from that context that you make the test. If you can’t think of that context, then I question whether it’s value-added code at all.

  • http://www.lostechies.com/members/derick.bailey/default.aspx derick.bailey

    @matt,

    sorry. got a little ambiguous, eh? :)

    i have considered passing ISomeRepository as a dependency along with IMyService, into the higher level object (a presenter in this case)… (then, the rest of what i said about my theory, etc.)

  • http://www.lostechies.com/members/derick.bailey/default.aspx derick.bailey

    @scott,

    yes, IMyService exists for a reason and I have a good number of specifications for the object that uses it, verifying that it calls IMyService correctly.

    assuming that there is no value / context for the pass through, would you suggest making ISomeRepository a dependency of the same object that depends on IMyService, like matt hinze is suggesting?

  • Matt Hinze

    I’m curious why you would want to avoid passing the same instance or dependency into multiple dependents in the graph. It seems fine to me if the service does something with the repository and the presenter does something with the service and the repository.

  • http://www.lostechies.com/members/derick.bailey/default.aspx derick.bailey

    @matt,

    yeah, like i said – it may be a dumb theory. the more i think about it and try to figure out why i think it’s bad, the more i realize that i don’t have any reason to think that.

    seems I am starting to lean toward killing that wrapper method and passing ISomeRepository into the same object that uses IMyService.

  • http://www.codebucket.org Lee Brandt

    I agree with Matt that if you are experiencing friction in your specs, then your specs are driving you toward an alternative design.

    That being said, I generally verify these kinds of calls in terms of use. For instance:

    When_searching_for_floogles — set up context and action
    Should_get_search_criteria_from_ui — verify call to UI
    Should_pass_search_criteria_to_search_service — varify call to service
    Should_get_floogles_matching_search_criteria — verify call to repository
    Should_return_floogles — verify repository returns correct matching floogles
    Should_display_found_floogles — verify the call to UI to display found floogles

    If I have other calls to the service, they are verified in those specs as well. This may make my specs a little “damp”, but I am OK with that.

    This has been my approach, for what it’s worth.

    Hope this helps,
    Lee

  • http://www.lostechies.com/members/scottcreynolds/default.aspx Scott C Reynolds

    @derick yeah obviously this is contrived, but if you can’t come up with a real case for a further abstraction, which usually you can tell if you have a hard time finding a reason to test it, then dump the pass-through and share the dependencies.

    my guess is that if you had a real specific reason to do it this way, you wouldn’t be asking questions about the tests, if you get what I mean. My experience is that when the test feels unnatural, it’s a sign i did something wrong.

  • http://www.lostechies.com/members/scottcreynolds/default.aspx Scott C Reynolds

    @derick catching up on the comments it seems like maybe you’re leaning that way.

    let the tests guide you, that’s why we use them. we experiment, then things feel unnatural or weird, so we fall back and trust that testing is design and not testing and listen to what they are telling us. this is the real power of BDD shining through.

  • http://scottbellware.com Scott Bellware

    Derick,

    Either take a dependency directly on the repository and get rid of that delegation, or make it clear in the spec that there’s a reason why a service interface and a data storage interface are different.

    Specifications for a client of the service will document “getting” a resource.

    Specifications for the service will document retrieval from storage (because the implementation uses the data storage module to do the “getting”).

    PersonService, when getting a person
    - should retrieve the person from storage

  • http://www.lostechies.com/members/derick.bailey/default.aspx derick.bailey

    @bellware

    hmmmm…. i think you may have solidified some of what i was thinking in the back of my head. so there is some good reason for creating a structure similar to what i’ve shown – but the language i’m using is obviously incorrect. it makes sense, though… i often hear people talking about retrieving something from a database or file… “go load xyz from this file, and do abc with it” … so that language would be represented in the different layers…

    presenter, when doing abc
    – should get the person to do it to

    personservice, when getting a person
    – should retrieve the person from the file (or database or whatever)

    then the question becomes one of what is really valuable and needed in the system, not “is this language correct”. do i really need to have yet another layer of indirection in this case? does the size and or complexity of the overall behavior in this part of the system warrant such a fine level of abstraction and redirection? or am i simply over-engineering this piece and creating more complexity than is needed.

    i think this gets back to what scott reynolds was saying about letting the tests be our design guide. such a fine grain abstraction and indirection felt odd to me, which is why i asked the question, so in this case that level of abstraction may not be needed.

    like everything else, thoug, “it depends” :) i can certainly see a need to have a fine grain abstraction like this in some scenarios. now i just need to listen to that voice in my head that keeps asking the questions, and learn to recognize the questions as a symptom or result of something more meaningful or fundamental.

  • http://scottbellware.com Scott Bellware

    When we stop believing in the answer being “it depends” we’re going to settle on one answer and start down the path to stagnation. It always depends, but that doesn’t mean that the resulting action should be willy-nilly. Whatever the answer is, I’m still going to try to bring the right experience and insight to bear, and sometimes this might mean making an exception to a well-traveled rule or going against some cultural orthodoxy. It depends of the content of the experience and insight.

    There are “right” answers. Picking the right “right” answer is the whole game. That, and knowing that what is “right” will change as perspective deepens and orthodoxies are understood and finer and finer levels of subtlety.

  • http://www.edgewolf.com/edus Nolan Egly

    I’m a little late on this conversation’s wrap up, but just thought I’d chime in since there’s been a lot of elaboration since my first read.

    Regarding the name of the test without any regard to the appropriateness of the object relationships it would probably be best to clarify “Should do something with SomeRepository” to clarify the pass through nature of the test.

    Regarding the appropriateness of the service, if it consists mainly of pass throughs to repositories, it’s probably not adding value unless you *know*, Real Soon Now, you’re adding other functionality to it. Services to me either provide a calculation outside a single domain object, or coordinate a single conceptual behavior across multiple domain objects when it isn’t appropriate to put that behavior on a single domain object.