Loading ...
Sorry, an error occurred while loading the content.

Re: [domaindrivendesign] Testing The Domain

Expand Messages
  • Eric Evans
    Colin, In reference to the first choice you layed out, I have a definite preference. ... I prefer real instances. Consider the things that often stop people
    Message 1 of 10 , Jul 22, 2007
    View Source
    • 0 Attachment
      Colin,

      In reference to the first choice you layed out, I have a definite
      preference.

      > 1) Use real instances of the domain classes.
      > 2) Use mock/dummy objects.

      I prefer real instances.

      Consider the things that often stop people from using this approach and
      push them toward mock/dummy objects. It may be difficult to create the
      objects because they require other objects (e.g. an Order object may
      require a Customer object which requires...). It may be difficult to
      create the objects because they depend on the infrastructure/other
      services (e.g. persistence, notification service...).

      I see these test writing difficulties as GOOD THINGS. The best models
      are decoupled into aggregates that can be created without too much
      fussing. One of the most common issues I see that undermine domain
      models on projects is over-coupling between domain objects. If you
      create real objects in the tests, your attention is drawn to these
      problems. Consider how the concept represented by the object could be
      meaningful without so much reference to the other concept.

      Coupling to the infrastructure is more recognized as a problem. Because
      it is more absolute (as in, we don't allow that at all, or only in a
      very specific way), it is easier to deal with than the coupled model
      problem (where we want to have some dependencies between domain objects,
      and choosing the right ones is an evolving model/design decision).

      By using dummy objects, both of these issues are swept under the rug.
      And I don't like to see lots of convenient "createOrder(...)" type
      methods implemented in the tests, either.

      The second choice you raise:
      > 1) See the factory as the entrypoint into the domain and test it
      > through its public interface.
      > 2) Write tests for the implementation details of the factory (or
      > service), for example testing internal/private parts of the factory.

      I think this one is not an either-or. A good factory is meant to be an
      abstraction layer, and so it should be tested that way. And part of the
      point of encapsulation is to give you freedom to modify the
      implementation, so you don't want to just bind yourself up again by
      testing the internals directly.

      On the other hand, we want the model to make sense alone, without the
      factory, so you need tests for the model objects and the basic ways the
      fit together.

      There may be some conflict between these goals, but I do both, focusing
      the tests on the high-risk parts and the parts I want to explain. If the
      conflict seems more than reasonable, consider if the factories are
      leaching logic out of the objects (yet another way to end up with an
      anemic model). The factory should assemble and orchestrate
      constraint-checking, but be watchful of it taking on more
      responsibilities. (In your case, I doubt that is happening, because you
      said you were coming down on the side of testing the objects directly.)

      Eric
    • David Laribee
      To me it comes down to how you define the unit. (I also recognize some people are nuts about interfaces and mocking, but... to each their own.) I treat the
      Message 2 of 10 , Jul 22, 2007
      View Source
      • 0 Attachment
        To me it comes down to how you define the unit. (I also recognize some people are nuts about interfaces and mocking, but... to each their own.)

        I treat the Aggregate as a unit. It's simply inelegant, IMHO, to create seams for collections, etc. I generally state test my Aggregates. You'll end up with a fixture-per-aggregate. A couple of strategically placed Factory Method inside your test fixture ( e.g. GetCustomerForThisScenario()) will do wonders for your sanity / test lengths. I tend to use what I call Testable Mask when things get hard to verify. That is, protected fields in the entity/aggregate that you can expose via a subclass where you perform the test.

        I treat Domain Services as a unit and test them in a mock style. I try to keep my tests down to one mock object and however many stubs (sometimes domain services have a number of dependencies).

        Most of my Repository code is factored into a base class that's tested elsewhere so I trust it. Custom repository methods I test in a mock style.

        Build-to-order and query specifications I generally test in a state-based manner. I'll include the AR they go against straight up.

        I generally implement factories as Factory Methods on a repository so not 100% sure about your scenario. I'll assume you're talking about a separate factory class. These, in my opinion, resemble closely domain services so I'd probably test that in a mock style ( e.g. constructor inject interfaces that are used to gather up the parts of the AR or make decisions about its assembly).

        I test-drive a lot of my design so I just live with the white box coupling. I don't find it too cumbersome especially after the design stabilizes. It's amazing how strictly adhering to Law of Demeter and Single Responsibility Principle will localize test maintenance when you do change implementation (where good SRP makes a rare event and LoD keeps the coupling low).


        / Dave

        http://thebeelog.com


        On 7/22/07, colin.jack < colin.jack@...> wrote:

        Hi,

        We're looking at how we test within our project and there has been a
        lot of discussion about which approach to prefer when setting up the
        environment for each test:

        1) Use real instances of the domain classes.
        2) Use mock/dummy objects.

        If we choose the first option then if we're testing Customer and the
        test requirest us to have an Order then we'd create a real Order
        object in the test setup, obviously if we go for the second on we'd
        have to mock the Order.

        So far we've chosen the first of the two options but the two
        different approaches have their own advantages/disadvantages so I'm
        interested in other peoples opinions.

        We've also been discussing at what level to test. For example if we
        have a Factory that takes one aggregate as an input and gives us back
        a fully populated instance of another aggregate then we have two
        further choices:

        1) See the factory as the entrypoint into the domain and test it
        through its public interface.
        2) Write tests for the implementation details of the factory (or
        service), for example testing internal/private parts of the factory.

        This is the problem I always meet with unit testing, if I test at a
        lower level (second option) then my tests are more coupled to the
        implementation but they are easier to read/maintain. Testing at a
        higher level makes the tests more complicated but you can refactor
        the implementation details without them breaking. So far when using
        DDD I've found the first type of test more useful but it is a
        difficult choice.

        Ta,

        Colin


      • Eric Evans
        David makes some interesting points. As I said a moment ago, I like to avoid factory methods in the text fixture. But I d be open minded if the project had
        Message 3 of 10 , Jul 22, 2007
        View Source
        • 0 Attachment
          David makes some interesting points.

          As I said a moment ago, I like to avoid factory methods in the text
          fixture. But I'd be open minded if the project had well-defined
          aggregates and the factory method was creating one, to be tested as a
          whole. (Of course, that factory behavior might also be useful to the
          app, so perhaps it could be the basis of a separate factory).
          Unfortunately, what I more often see with those factory methods in tests
          is that they are compensating for the lack of clear aggregate boundaries.

          Also a good point about domain services tending to have legitimate
          dependencies, hence mocking them makes sense in many tests. For example,
          in timeandmoney, the "TimeSource" interface enables this approach. Most
          real TimeSource implementations are coupled to something external to the
          program (the system clock, an Internet time service) and you don't want
          that intruding on your tests. To test application logic that uses a
          TimeSource, you need a dummy of some kind that returns a known value and
          doesn't make the test dependent on some external resource (even though
          the live program will be).

          Interesting description of testing the factories by giving them mocks to
          assemble. (If I understood.) The upside of that would be to discourage
          the factory from becoming more than a factory.

          They are necessary some times, and can be used well, but I still see
          mocks more often covering up model/design problems.

          Eric

          P.S. By the way, I prefer not to put factory methods in the repository.
          Seems to blur its responsibility of being the access point for obtaining
          preexisting objects. Factories make new objects.



          David Laribee wrote:
          >
          >
          >
          > I treat the Aggregate as a unit. It's simply inelegant, IMHO, to
          > create seams for collections, etc. I generally state test my
          > Aggregates. You'll end up with a fixture-per-aggregate. A couple of
          > strategically placed Factory Method inside your test fixture ( e.g.
          > GetCustomerForThisScenario()) will do wonders for your sanity / test
          > lengths. I tend to use what I call Testable Mask when things get hard
          > to verify. That is, protected fields in the entity/aggregate that you
          > can expose via a subclass where you perform the test.
          >
          > I treat Domain Services as a unit and test them in a mock style. I try
          > to keep my tests down to one mock object and however many stubs
          > (sometimes domain services have a number of dependencies).
          >
          > .
          > _,___
        • colin.jack
          Hi, Thanks for the superb reply, really gives weight to our approach and its great to get such a well thought out reply. On the factory front I think I
          Message 4 of 10 , Jul 22, 2007
          View Source
          • 0 Attachment
            Hi,

            Thanks for the superb reply, really gives weight to our approach and
            its great to get such a well thought out reply.

            On the factory front I think I confused things. We've just got one
            factory that is quite complex its got all sorts of rules about the
            shape of the aggregate. Currently the factories implementation uses
            one approach (strategy pattern) to handle this complexity but it
            could use other designs. Testing wise the choice is between:

            1) Test the strategies directly, coupling the tests to the
            implementation but aiding readability (and maintainability?) of the
            tests.
            2) Just test the factory through its public interface, so although
            each strategy is tested the tests don't know the strategy pattern is
            used.

            I don't see either approach as perfect, we've normally gone for the
            second of the two solutions but it is questionable which is better.

            Ta,

            Colin


            --- In domaindrivendesign@yahoogroups.com, Eric Evans <eric@...>
            wrote:
            >
            > Colin,
            >
            > In reference to the first choice you layed out, I have a definite
            > preference.
            >
            > > 1) Use real instances of the domain classes.
            > > 2) Use mock/dummy objects.
            >
            > I prefer real instances.
            >
            > Consider the things that often stop people from using this approach
            and
            > push them toward mock/dummy objects. It may be difficult to create
            the
            > objects because they require other objects (e.g. an Order object
            may
            > require a Customer object which requires...). It may be difficult
            to
            > create the objects because they depend on the infrastructure/other
            > services (e.g. persistence, notification service...).
            >
            > I see these test writing difficulties as GOOD THINGS. The best
            models
            > are decoupled into aggregates that can be created without too much
            > fussing. One of the most common issues I see that undermine domain
            > models on projects is over-coupling between domain objects. If you
            > create real objects in the tests, your attention is drawn to these
            > problems. Consider how the concept represented by the object could
            be
            > meaningful without so much reference to the other concept.
            >
            > Coupling to the infrastructure is more recognized as a problem.
            Because
            > it is more absolute (as in, we don't allow that at all, or only in
            a
            > very specific way), it is easier to deal with than the coupled
            model
            > problem (where we want to have some dependencies between domain
            objects,
            > and choosing the right ones is an evolving model/design decision).
            >
            > By using dummy objects, both of these issues are swept under the
            rug.
            > And I don't like to see lots of convenient "createOrder(...)" type
            > methods implemented in the tests, either.
            >
            > The second choice you raise:
            > > 1) See the factory as the entrypoint into the domain and test it
            > > through its public interface.
            > > 2) Write tests for the implementation details of the factory (or
            > > service), for example testing internal/private parts of the
            factory.
            >
            > I think this one is not an either-or. A good factory is meant to be
            an
            > abstraction layer, and so it should be tested that way. And part of
            the
            > point of encapsulation is to give you freedom to modify the
            > implementation, so you don't want to just bind yourself up again by
            > testing the internals directly.
            >
            > On the other hand, we want the model to make sense alone, without
            the
            > factory, so you need tests for the model objects and the basic ways
            the
            > fit together.
            >
            > There may be some conflict between these goals, but I do both,
            focusing
            > the tests on the high-risk parts and the parts I want to explain.
            If the
            > conflict seems more than reasonable, consider if the factories are
            > leaching logic out of the objects (yet another way to end up with
            an
            > anemic model). The factory should assemble and orchestrate
            > constraint-checking, but be watchful of it taking on more
            > responsibilities. (In your case, I doubt that is happening, because
            you
            > said you were coming down on the side of testing the objects
            directly.)
            >
            > Eric
            >
          • colin.jack
            Hi Eric, I ve been thinking more about what you have said about the need to have test object factories and I want to pick your brain a bit a bit more on it.
            Message 5 of 10 , Jul 24, 2007
            View Source
            • 0 Attachment
              Hi Eric,

              I've been thinking more about what you have said about the need to
              have test object factories and I want to pick your brain a bit a bit
              more on it.

              Take the example you gave, a Customer and Order. Lets say that when
              doing a test we need a Customer and we need it to be in the Active
              state. However we also have a business rule that to get into the
              Active state the Customer must have at least one complete Order, so
              we've implemented that rule checking within the Customer.

              The approach we've been taking is to have TestCustomerFactory with
              methods like CreateActiveClient(). Inside that method it will create
              a Customer, create and assign an Order and then transition one or
              both objects until the Customer is in the Active state.

              Do you think this approach makes sense or would you do something
              different?

              If we said that the rule about an Active Customer having to have a
              completed Order is a cross aggregate rule then it does not need to be
              handled by the Customer aggregate, which could improve things from a
              testing standpoint?

              Thanks,

              Colin

              --- In domaindrivendesign@yahoogroups.com, Eric Evans <eric@...>
              wrote:
              >
              > Colin,
              >
              > In reference to the first choice you layed out, I have a definite
              > preference.
              >
              > > 1) Use real instances of the domain classes.
              > > 2) Use mock/dummy objects.
              >
              > I prefer real instances.
              >
              > Consider the things that often stop people from using this approach
              and
              > push them toward mock/dummy objects. It may be difficult to create
              the
              > objects because they require other objects (e.g. an Order object
              may
              > require a Customer object which requires...). It may be difficult
              to
              > create the objects because they depend on the infrastructure/other
              > services (e.g. persistence, notification service...).
              >
              > I see these test writing difficulties as GOOD THINGS. The best
              models
              > are decoupled into aggregates that can be created without too much
              > fussing. One of the most common issues I see that undermine domain
              > models on projects is over-coupling between domain objects. If you
              > create real objects in the tests, your attention is drawn to these
              > problems. Consider how the concept represented by the object could
              be
              > meaningful without so much reference to the other concept.
              >
              > Coupling to the infrastructure is more recognized as a problem.
              Because
              > it is more absolute (as in, we don't allow that at all, or only in
              a
              > very specific way), it is easier to deal with than the coupled
              model
              > problem (where we want to have some dependencies between domain
              objects,
              > and choosing the right ones is an evolving model/design decision).
              >
              > By using dummy objects, both of these issues are swept under the
              rug.
              > And I don't like to see lots of convenient "createOrder(...)" type
              > methods implemented in the tests, either.
              >
              > The second choice you raise:
              > > 1) See the factory as the entrypoint into the domain and test it
              > > through its public interface.
              > > 2) Write tests for the implementation details of the factory (or
              > > service), for example testing internal/private parts of the
              factory.
              >
              > I think this one is not an either-or. A good factory is meant to be
              an
              > abstraction layer, and so it should be tested that way. And part of
              the
              > point of encapsulation is to give you freedom to modify the
              > implementation, so you don't want to just bind yourself up again by
              > testing the internals directly.
              >
              > On the other hand, we want the model to make sense alone, without
              the
              > factory, so you need tests for the model objects and the basic ways
              the
              > fit together.
              >
              > There may be some conflict between these goals, but I do both,
              focusing
              > the tests on the high-risk parts and the parts I want to explain.
              If the
              > conflict seems more than reasonable, consider if the factories are
              > leaching logic out of the objects (yet another way to end up with
              an
              > anemic model). The factory should assemble and orchestrate
              > constraint-checking, but be watchful of it taking on more
              > responsibilities. (In your case, I doubt that is happening, because
              you
              > said you were coming down on the side of testing the objects
              directly.)
              >
              > Eric
              >
            • carel.lotz
              The test factory approach sort of resembles the ObjectMother pattern where you create test factories whose sole purpose is to create test objects and to tailor
              Message 6 of 10 , Jul 24, 2007
              View Source
              • 0 Attachment
                The test factory approach sort of resembles the ObjectMother pattern
                where you create test factories whose sole purpose is to create test
                objects and to tailor those objects at any point during the testing
                process.

                We started creating ObjectMothers for state testing our domain, but
                because the domain was changing a lot, we found that we spend a lot of
                time refactoring the test code. At the end we opted for creating a
                fluent interface for our test factories using what Martin Fowler has
                coined as ExpressionBuilders. I blogged about it here:

                http://dotnet.org.za/cjlotz/archive/2007/01/09/using-a-dsl-to-create-a-fluent-interface-for-unit-testing-your-domain-model.aspx

                We are much happier with this approach as the test scenarios are
                easier to maintain, construct and understand.

                --- In domaindrivendesign@yahoogroups.com, "colin.jack"
                <colin.jack@...> wrote:
                >
                > Hi Eric,
                >
                > I've been thinking more about what you have said about the need to
                > have test object factories and I want to pick your brain a bit a bit
                > more on it.
                >
                > Take the example you gave, a Customer and Order. Lets say that when
                > doing a test we need a Customer and we need it to be in the Active
                > state. However we also have a business rule that to get into the
                > Active state the Customer must have at least one complete Order, so
                > we've implemented that rule checking within the Customer.
                >
                > The approach we've been taking is to have TestCustomerFactory with
                > methods like CreateActiveClient(). Inside that method it will create
                > a Customer, create and assign an Order and then transition one or
                > both objects until the Customer is in the Active state.
                >
                > Do you think this approach makes sense or would you do something
                > different?
                >
                > If we said that the rule about an Active Customer having to have a
                > completed Order is a cross aggregate rule then it does not need to be
                > handled by the Customer aggregate, which could improve things from a
                > testing standpoint?
                >
                > Thanks,
                >
                > Colin
                >
                > --- In domaindrivendesign@yahoogroups.com, Eric Evans <eric@>
                > wrote:
                > >
                > > Colin,
                > >
                > > In reference to the first choice you layed out, I have a definite
                > > preference.
                > >
                > > > 1) Use real instances of the domain classes.
                > > > 2) Use mock/dummy objects.
                > >
                > > I prefer real instances.
                > >
                > > Consider the things that often stop people from using this approach
                > and
                > > push them toward mock/dummy objects. It may be difficult to create
                > the
                > > objects because they require other objects (e.g. an Order object
                > may
                > > require a Customer object which requires...). It may be difficult
                > to
                > > create the objects because they depend on the infrastructure/other
                > > services (e.g. persistence, notification service...).
                > >
                > > I see these test writing difficulties as GOOD THINGS. The best
                > models
                > > are decoupled into aggregates that can be created without too much
                > > fussing. One of the most common issues I see that undermine domain
                > > models on projects is over-coupling between domain objects. If you
                > > create real objects in the tests, your attention is drawn to these
                > > problems. Consider how the concept represented by the object could
                > be
                > > meaningful without so much reference to the other concept.
                > >
                > > Coupling to the infrastructure is more recognized as a problem.
                > Because
                > > it is more absolute (as in, we don't allow that at all, or only in
                > a
                > > very specific way), it is easier to deal with than the coupled
                > model
                > > problem (where we want to have some dependencies between domain
                > objects,
                > > and choosing the right ones is an evolving model/design decision).
                > >
                > > By using dummy objects, both of these issues are swept under the
                > rug.
                > > And I don't like to see lots of convenient "createOrder(...)" type
                > > methods implemented in the tests, either.
                > >
                > > The second choice you raise:
                > > > 1) See the factory as the entrypoint into the domain and test it
                > > > through its public interface.
                > > > 2) Write tests for the implementation details of the factory (or
                > > > service), for example testing internal/private parts of the
                > factory.
                > >
                > > I think this one is not an either-or. A good factory is meant to be
                > an
                > > abstraction layer, and so it should be tested that way. And part of
                > the
                > > point of encapsulation is to give you freedom to modify the
                > > implementation, so you don't want to just bind yourself up again by
                > > testing the internals directly.
                > >
                > > On the other hand, we want the model to make sense alone, without
                > the
                > > factory, so you need tests for the model objects and the basic ways
                > the
                > > fit together.
                > >
                > > There may be some conflict between these goals, but I do both,
                > focusing
                > > the tests on the high-risk parts and the parts I want to explain.
                > If the
                > > conflict seems more than reasonable, consider if the factories are
                > > leaching logic out of the objects (yet another way to end up with
                > an
                > > anemic model). The factory should assemble and orchestrate
                > > constraint-checking, but be watchful of it taking on more
                > > responsibilities. (In your case, I doubt that is happening, because
                > you
                > > said you were coming down on the side of testing the objects
                > directly.)
                > >
                > > Eric
                > >
                >
              • carel.lotz
                The whole test factory approach resembles the ObjectMother test pattern where you create test factories whose sole purpose is to create test objects and to
                Message 7 of 10 , Jul 25, 2007
                View Source
                • 0 Attachment
                  The whole test factory approach resembles the ObjectMother test
                  pattern where you create test factories whose sole purpose is to
                  create test objects and to tailor those objects at any point during
                  the testing process.

                  We started creating ObjectMothers for state testing our domain, but
                  because the domain was changing a lot, we found that we spend a lot of
                  time refactoring the test factory code. At the end we opted for
                  creating a fluent interface for our test factories using what Martin
                  Fowler has coined as ExpressionBuilders. I blogged about it here:

                  http://dotnet.org.za/cjlotz/archive/2007/01/09/using-a-dsl-to-create-a-fluent-interface-for-unit-testing-your-domain-model.aspx

                  We are much happier with this approach as the test scenarios are
                  easier to maintain, construct and understand.

                  > The approach we've been taking is to have TestCustomerFactory with
                  > methods like CreateActiveClient(). Inside that method it will create
                  > a Customer, create and assign an Order and then transition one or
                  > both objects until the Customer is in the Active state.
                  >
                • colin.jack
                  You are quite right, what we re doing is very similiar to ObjectMother and your post was very interesting, I ve posted a few questions in comments on it. I
                  Message 8 of 10 , Jul 30, 2007
                  View Source
                  • 0 Attachment
                    You are quite right, what we're doing is very similiar to
                    ObjectMother and your post was very interesting, I've posted a few
                    questions in comments on it.

                    I have a few further questions though:

                    1) How the DSL/builder approach helped solve the issue of you having
                    to change this sort of code when the domain changes?
                    2) How do state transitions fit into the builder/DSL approach, say
                    you needed a Person in state X do you just do that in the builder as
                    you would with ObjectMother?
                    3) How do you handle situations where the objects you are creating
                    are in multiple aggregates? Do you chain together your builders as
                    you would with ObjectMother?

                    Ta,

                    Colin

                    --- In domaindrivendesign@yahoogroups.com, "colin.jack"
                    <colin.jack@...> wrote:
                    >
                    > Really good thanks, I've posted a few questions in comments on the
                    > blog.
                    >
                    > You are quite right, what we're doing is very similiar to
                    > ObjectMother.
                    >
                    > I'm interested to know how the DSL approach helped solve the issue
                    of
                    > you having to change the ObjectMother code when the domain changed
                    > and how state transitions fit into the Builder approach?
                    >
                    > --- In domaindrivendesign@yahoogroups.com, "carel.lotz"
                    > <carel.lotz@> wrote:
                    > >
                    > > The test factory approach sort of resembles the ObjectMother
                    pattern
                    > > where you create test factories whose sole purpose is to create
                    test
                    > > objects and to tailor those objects at any point during the
                    testing
                    > > process.
                    > >
                    > > We started creating ObjectMothers for state testing our domain,
                    but
                    > > because the domain was changing a lot, we found that we spend a
                    lot
                    > of
                    > > time refactoring the test code. At the end we opted for creating
                    a
                    > > fluent interface for our test factories using what Martin Fowler
                    has
                    > > coined as ExpressionBuilders. I blogged about it here:
                    > >
                    > > http://dotnet.org.za/cjlotz/archive/2007/01/09/using-a-dsl-to-
                    > create-a-fluent-interface-for-unit-testing-your-domain-model.aspx
                    > >
                    > > We are much happier with this approach as the test scenarios are
                    > > easier to maintain, construct and understand.
                    > >
                    > > --- In domaindrivendesign@yahoogroups.com, "colin.jack"
                    > > <colin.jack@> wrote:
                    > > >
                    > > > Hi Eric,
                    > > >
                    > > > I've been thinking more about what you have said about the need
                    > to
                    > > > have test object factories and I want to pick your brain a bit
                    a
                    > bit
                    > > > more on it.
                    > > >
                    > > > Take the example you gave, a Customer and Order. Lets say that
                    > when
                    > > > doing a test we need a Customer and we need it to be in the
                    > Active
                    > > > state. However we also have a business rule that to get into
                    the
                    > > > Active state the Customer must have at least one complete
                    Order,
                    > so
                    > > > we've implemented that rule checking within the Customer.
                    > > >
                    > > > The approach we've been taking is to have TestCustomerFactory
                    > with
                    > > > methods like CreateActiveClient(). Inside that method it will
                    > create
                    > > > a Customer, create and assign an Order and then transition one
                    or
                    > > > both objects until the Customer is in the Active state.
                    > > >
                    > > > Do you think this approach makes sense or would you do
                    something
                    > > > different?
                    > > >
                    > > > If we said that the rule about an Active Customer having to
                    have
                    > a
                    > > > completed Order is a cross aggregate rule then it does not need
                    > to be
                    > > > handled by the Customer aggregate, which could improve things
                    > from a
                    > > > testing standpoint?
                    > > >
                    > > > Thanks,
                    > > >
                    > > > Colin
                    > > >
                    > > > --- In domaindrivendesign@yahoogroups.com, Eric Evans <eric@>
                    > > > wrote:
                    > > > >
                    > > > > Colin,
                    > > > >
                    > > > > In reference to the first choice you layed out, I have a
                    > definite
                    > > > > preference.
                    > > > >
                    > > > > > 1) Use real instances of the domain classes.
                    > > > > > 2) Use mock/dummy objects.
                    > > > >
                    > > > > I prefer real instances.
                    > > > >
                    > > > > Consider the things that often stop people from using this
                    > approach
                    > > > and
                    > > > > push them toward mock/dummy objects. It may be difficult to
                    > create
                    > > > the
                    > > > > objects because they require other objects (e.g. an Order
                    > object
                    > > > may
                    > > > > require a Customer object which requires...). It may be
                    > difficult
                    > > > to
                    > > > > create the objects because they depend on the
                    > infrastructure/other
                    > > > > services (e.g. persistence, notification service...).
                    > > > >
                    > > > > I see these test writing difficulties as GOOD THINGS. The
                    best
                    > > > models
                    > > > > are decoupled into aggregates that can be created without too
                    > much
                    > > > > fussing. One of the most common issues I see that undermine
                    > domain
                    > > > > models on projects is over-coupling between domain objects.
                    If
                    > you
                    > > > > create real objects in the tests, your attention is drawn to
                    > these
                    > > > > problems. Consider how the concept represented by the object
                    > could
                    > > > be
                    > > > > meaningful without so much reference to the other concept.
                    > > > >
                    > > > > Coupling to the infrastructure is more recognized as a
                    problem.
                    > > > Because
                    > > > > it is more absolute (as in, we don't allow that at all, or
                    only
                    > in
                    > > > a
                    > > > > very specific way), it is easier to deal with than the
                    coupled
                    > > > model
                    > > > > problem (where we want to have some dependencies between
                    domain
                    > > > objects,
                    > > > > and choosing the right ones is an evolving model/design
                    > decision).
                    > > > >
                    > > > > By using dummy objects, both of these issues are swept under
                    > the
                    > > > rug.
                    > > > > And I don't like to see lots of convenient "createOrder(...)"
                    > type
                    > > > > methods implemented in the tests, either.
                    > > > >
                    > > > > The second choice you raise:
                    > > > > > 1) See the factory as the entrypoint into the domain and
                    test
                    > it
                    > > > > > through its public interface.
                    > > > > > 2) Write tests for the implementation details of the
                    factory
                    > (or
                    > > > > > service), for example testing internal/private parts of the
                    > > > factory.
                    > > > >
                    > > > > I think this one is not an either-or. A good factory is meant
                    > to be
                    > > > an
                    > > > > abstraction layer, and so it should be tested that way. And
                    > part of
                    > > > the
                    > > > > point of encapsulation is to give you freedom to modify the
                    > > > > implementation, so you don't want to just bind yourself up
                    > again by
                    > > > > testing the internals directly.
                    > > > >
                    > > > > On the other hand, we want the model to make sense alone,
                    > without
                    > > > the
                    > > > > factory, so you need tests for the model objects and the
                    basic
                    > ways
                    > > > the
                    > > > > fit together.
                    > > > >
                    > > > > There may be some conflict between these goals, but I do
                    both,
                    > > > focusing
                    > > > > the tests on the high-risk parts and the parts I want to
                    > explain.
                    > > > If the
                    > > > > conflict seems more than reasonable, consider if the
                    factories
                    > are
                    > > > > leaching logic out of the objects (yet another way to end up
                    > with
                    > > > an
                    > > > > anemic model). The factory should assemble and orchestrate
                    > > > > constraint-checking, but be watchful of it taking on more
                    > > > > responsibilities. (In your case, I doubt that is happening,
                    > because
                    > > > you
                    > > > > said you were coming down on the side of testing the objects
                    > > > directly.)
                    > > > >
                    > > > > Eric
                    > > > >
                    > > >
                    > >
                    >
                  • colin.jack
                    Great post thanks, you are definitely right that after the design stabilizes the tests being coupled to the implementation isn t a problem but up till that
                    Message 9 of 10 , Jul 30, 2007
                    View Source
                    • 0 Attachment
                      Great post thanks, you are definitely right that after the design
                      stabilizes the tests being coupled to the implementation isn't a
                      problem but up till that point I've found it troublesome when you
                      refactor. Tricky choice though.

                      Aggregate as a unit seems fair enough, in our approach though we use
                      a lot of test factory methods, particularly to get objects into
                      particular states ready for tests (e.g. give me a customer that is in
                      the Active state). The bit that Eric picks up on is that it gets more
                      complex where we have cross aggregate associations and related rules,
                      such as that an Order must be associated with a Customer so when you
                      create a test Order you must have a test Customer. I don't know what
                      to do about this, if its a hard domain rule then you need to have the
                      association at one end.

                      The bit about testing domain services is useful, I will consider that
                      when I next come to test one. Not sure about the Testable Mask idea,
                      seen that sort of approach before but if we do need to break
                      encapsulation we tend to use reflection these days which we've found
                      works quite nicely.



                      --- In domaindrivendesign@yahoogroups.com, "David Laribee"
                      <david@...> wrote:
                      >
                      > To me it comes down to how you define the unit. (I also recognize
                      some
                      > people are nuts about interfaces and mocking, but... to each their
                      own.)
                      >
                      > I treat the Aggregate as a unit. It's simply inelegant, IMHO, to
                      create
                      > seams for collections, etc. I generally state test my Aggregates.
                      You'll end
                      > up with a fixture-per-aggregate. A couple of strategically placed
                      Factory
                      > Method inside your test fixture (e.g. GetCustomerForThisScenario())
                      will do
                      > wonders for your sanity / test lengths. I tend to use what I call
                      Testable
                      > Mask when things get hard to verify. That is, protected fields in
                      the
                      > entity/aggregate that you can expose via a subclass where you
                      perform the
                      > test.
                      >
                      > I treat Domain Services as a unit and test them in a mock style. I
                      try to
                      > keep my tests down to one mock object and however many stubs
                      (sometimes
                      > domain services have a number of dependencies).
                      >
                      > Most of my Repository code is factored into a base class that's
                      tested
                      > elsewhere so I trust it. Custom repository methods I test in a mock
                      style.
                      >
                      > Build-to-order and query specifications I generally test in a state-
                      based
                      > manner. I'll include the AR they go against straight up.
                      >
                      > I generally implement factories as Factory Methods on a repository
                      so not
                      > 100% sure about your scenario. I'll assume you're talking about a
                      separate
                      > factory class. These, in my opinion, resemble closely domain
                      services so I'd
                      > probably test that in a mock style (e.g. constructor inject
                      interfaces that
                      > are used to gather up the parts of the AR or make decisions about
                      its
                      > assembly).
                      >
                      > I test-drive a lot of my design so I just live with the white box
                      coupling.
                      > I don't find it too cumbersome especially after the design
                      stabilizes. It's
                      > amazing how strictly adhering to Law of Demeter and Single
                      Responsibility
                      > Principle will localize test maintenance when you do change
                      implementation
                      > (where good SRP makes a rare event and LoD keeps the coupling low).
                      >
                      >
                      > / Dave
                      >
                      > http://thebeelog.com
                      >
                      >
                      > On 7/22/07, colin.jack <colin.jack@...> wrote:
                      > >
                      > > Hi,
                      > >
                      > > We're looking at how we test within our project and there has
                      been a
                      > > lot of discussion about which approach to prefer when setting up
                      the
                      > > environment for each test:
                      > >
                      > > 1) Use real instances of the domain classes.
                      > > 2) Use mock/dummy objects.
                      > >
                      > > If we choose the first option then if we're testing Customer and
                      the
                      > > test requirest us to have an Order then we'd create a real Order
                      > > object in the test setup, obviously if we go for the second on
                      we'd
                      > > have to mock the Order.
                      > >
                      > > So far we've chosen the first of the two options but the two
                      > > different approaches have their own advantages/disadvantages so
                      I'm
                      > > interested in other peoples opinions.
                      > >
                      > > We've also been discussing at what level to test. For example if
                      we
                      > > have a Factory that takes one aggregate as an input and gives us
                      back
                      > > a fully populated instance of another aggregate then we have two
                      > > further choices:
                      > >
                      > > 1) See the factory as the entrypoint into the domain and test it
                      > > through its public interface.
                      > > 2) Write tests for the implementation details of the factory (or
                      > > service), for example testing internal/private parts of the
                      factory.
                      > >
                      > > This is the problem I always meet with unit testing, if I test at
                      a
                      > > lower level (second option) then my tests are more coupled to the
                      > > implementation but they are easier to read/maintain. Testing at a
                      > > higher level makes the tests more complicated but you can refactor
                      > > the implementation details without them breaking. So far when
                      using
                      > > DDD I've found the first type of test more useful but it is a
                      > > difficult choice.
                      > >
                      > > Ta,
                      > >
                      > > Colin
                      > >
                      > >
                      > >
                      >
                    Your message has been successfully submitted and would be delivered to recipients shortly.