Struggling with cyclical dependencies in unit testsWhat is the value of checking in failing unit tests?Unit test strategy for layered (or derived) method callsAre HSQLDB unit tests an anti pattern?Designing unit tests for a stateful systemWhat's the idea behind mocking data access in unit testsUnit testing implementation vs behaviourHow to reconcile “not mocking what you don't own” with “expectations” in unit tests?Unit testing trivial casesUnit test a generic floating point equality functionDoes it matter how I setup test data when creating unit tests?

Not understanding how the gain works in the 1st stage of an instrumentation amplifier

What are these mathematical groups in U.S. universities?

Can ads on a page read my password?

Sparse matrix processing: flip sign of top-left entries of the matrix

Capacitors with a "/" on schematic

Why do private jets such as Gulfstream fly higher than other civilian jets?

sytemctl status log output

Why does putting a dot after the URL remove login information?

Finish the Mastermind

Can a character take on additional backgrounds, or at least their benefits?

Does the Voyager team use a wrapper (Fortran(77?) to Python) to transmit current commands?

Independent table row spacing

What was the first multiprocessor x86 motherboard?

Does this put me at risk for identity theft?

Does this smartphone photo show Mars just below the Sun?

How to realistically deal with a shield user?

Our group keeps dying during the Lost Mine of Phandelver campaign. What are we doing wrong?

Do other countries guarantee freedoms that the United States does not have?

Looking for a new job because of relocation - is it okay to tell the real reason?

ESTA declined to the US

WordCloud: do not eliminate duplicates

Is it allowed and safe to carry a passenger / non-pilot in the front seat of a small general aviation airplane?

Why do proponents of guns oppose gun competency tests?

Will a paper be retracted if a flaw in released software code invalidates its central idea?



Struggling with cyclical dependencies in unit tests


What is the value of checking in failing unit tests?Unit test strategy for layered (or derived) method callsAre HSQLDB unit tests an anti pattern?Designing unit tests for a stateful systemWhat's the idea behind mocking data access in unit testsUnit testing implementation vs behaviourHow to reconcile “not mocking what you don't own” with “expectations” in unit tests?Unit testing trivial casesUnit test a generic floating point equality functionDoes it matter how I setup test data when creating unit tests?






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








23















I'm trying to practice TDD, by using it to develop a simple like Bit Vector. I happen to be using Swift, but this is a language-agnostic question.



My BitVector is a struct that stores a single UInt64, and presents an API over it that lets you treat it like a collection. The details don't matter much, but it's pretty simple. The high 57 bits are storage bits, and the lower 6 bits are "count" bits, which tells you how many of the storage bits actually store a contained value.



So far, I have a handful of very simple capabilities:



  1. An initializer that constructs empty bit vectors

  2. A count property of type Int

  3. An isEmpty property of type Bool

  4. An equality operator (==). NB: this is a value-equality operator akin to Object.equals() in Java, not a reference equality operator like == in Java.

I'm running into a bunch of cyclical dependancies:




  1. The unit test that tests my initializer need to verify that the newly constructed BitVector. It can do so in one of 3 ways:



    1. Check bv.count == 0

    2. Check bv.isEmpty == true

    3. Check that bv == knownEmptyBitVector

    Method 1 relies on count, method 2 relies on isEmpty (which itself relies on count, so there's no point using it), method 3 relies on ==. In any case, I can't test my initializer in isolation.



  2. The test for count needs to operate on something, which inevitably tests my initializer(s)


  3. The implementation of isEmpty relies on count


  4. The implementation of == relies on count.


I was able to partly solve this problem by introducing a private API that constructs a BitVector from an existing bit pattern (as a UInt64). This allowed me to initialize values without testing any other initializers, so that I could "boot strap" my way up.



For my unit tests to truly be unit tests, I find myself doing a bunch of hacks, which complicate my prod and test code substantially.



How exactly do you get around these sorts of issues?










share|improve this question





















  • 20





    You are taking a too narrow view on the term "unit". BitVectoris a perfectly fine unit size for unit testing and immediately resolves your issues that public members of BitVector need each other to make meaningful tests.

    – Bart van Ingen Schenau
    Jul 29 at 9:09











  • You know too much implementation details up front. Is your development really test-driven?

    – herby
    Jul 30 at 20:44











  • @herby No, that's why I'm practicing. Although that seems like a really unattainable standard. I don't thing I've ever programmed anything without a pretty clear mental approximation of what the implementation will entail.

    – Alexander
    Jul 30 at 20:50











  • @Alexander You should try to relax that, otherwise it will be test-first, but not test-driven. Just say vague "I'll do a bit vector with one 64bit int as a backing store" and that's it; from that point on do TDD red-green-refactor one after another. Implementation details, as well as API, should emerge from trying to make tests run (the former), and from writing those tests in the first place (the latter).

    – herby
    Jul 30 at 20:54


















23















I'm trying to practice TDD, by using it to develop a simple like Bit Vector. I happen to be using Swift, but this is a language-agnostic question.



My BitVector is a struct that stores a single UInt64, and presents an API over it that lets you treat it like a collection. The details don't matter much, but it's pretty simple. The high 57 bits are storage bits, and the lower 6 bits are "count" bits, which tells you how many of the storage bits actually store a contained value.



So far, I have a handful of very simple capabilities:



  1. An initializer that constructs empty bit vectors

  2. A count property of type Int

  3. An isEmpty property of type Bool

  4. An equality operator (==). NB: this is a value-equality operator akin to Object.equals() in Java, not a reference equality operator like == in Java.

I'm running into a bunch of cyclical dependancies:




  1. The unit test that tests my initializer need to verify that the newly constructed BitVector. It can do so in one of 3 ways:



    1. Check bv.count == 0

    2. Check bv.isEmpty == true

    3. Check that bv == knownEmptyBitVector

    Method 1 relies on count, method 2 relies on isEmpty (which itself relies on count, so there's no point using it), method 3 relies on ==. In any case, I can't test my initializer in isolation.



  2. The test for count needs to operate on something, which inevitably tests my initializer(s)


  3. The implementation of isEmpty relies on count


  4. The implementation of == relies on count.


I was able to partly solve this problem by introducing a private API that constructs a BitVector from an existing bit pattern (as a UInt64). This allowed me to initialize values without testing any other initializers, so that I could "boot strap" my way up.



For my unit tests to truly be unit tests, I find myself doing a bunch of hacks, which complicate my prod and test code substantially.



How exactly do you get around these sorts of issues?










share|improve this question





















  • 20





    You are taking a too narrow view on the term "unit". BitVectoris a perfectly fine unit size for unit testing and immediately resolves your issues that public members of BitVector need each other to make meaningful tests.

    – Bart van Ingen Schenau
    Jul 29 at 9:09











  • You know too much implementation details up front. Is your development really test-driven?

    – herby
    Jul 30 at 20:44











  • @herby No, that's why I'm practicing. Although that seems like a really unattainable standard. I don't thing I've ever programmed anything without a pretty clear mental approximation of what the implementation will entail.

    – Alexander
    Jul 30 at 20:50











  • @Alexander You should try to relax that, otherwise it will be test-first, but not test-driven. Just say vague "I'll do a bit vector with one 64bit int as a backing store" and that's it; from that point on do TDD red-green-refactor one after another. Implementation details, as well as API, should emerge from trying to make tests run (the former), and from writing those tests in the first place (the latter).

    – herby
    Jul 30 at 20:54














23












23








23


6






I'm trying to practice TDD, by using it to develop a simple like Bit Vector. I happen to be using Swift, but this is a language-agnostic question.



My BitVector is a struct that stores a single UInt64, and presents an API over it that lets you treat it like a collection. The details don't matter much, but it's pretty simple. The high 57 bits are storage bits, and the lower 6 bits are "count" bits, which tells you how many of the storage bits actually store a contained value.



So far, I have a handful of very simple capabilities:



  1. An initializer that constructs empty bit vectors

  2. A count property of type Int

  3. An isEmpty property of type Bool

  4. An equality operator (==). NB: this is a value-equality operator akin to Object.equals() in Java, not a reference equality operator like == in Java.

I'm running into a bunch of cyclical dependancies:




  1. The unit test that tests my initializer need to verify that the newly constructed BitVector. It can do so in one of 3 ways:



    1. Check bv.count == 0

    2. Check bv.isEmpty == true

    3. Check that bv == knownEmptyBitVector

    Method 1 relies on count, method 2 relies on isEmpty (which itself relies on count, so there's no point using it), method 3 relies on ==. In any case, I can't test my initializer in isolation.



  2. The test for count needs to operate on something, which inevitably tests my initializer(s)


  3. The implementation of isEmpty relies on count


  4. The implementation of == relies on count.


I was able to partly solve this problem by introducing a private API that constructs a BitVector from an existing bit pattern (as a UInt64). This allowed me to initialize values without testing any other initializers, so that I could "boot strap" my way up.



For my unit tests to truly be unit tests, I find myself doing a bunch of hacks, which complicate my prod and test code substantially.



How exactly do you get around these sorts of issues?










share|improve this question
















I'm trying to practice TDD, by using it to develop a simple like Bit Vector. I happen to be using Swift, but this is a language-agnostic question.



My BitVector is a struct that stores a single UInt64, and presents an API over it that lets you treat it like a collection. The details don't matter much, but it's pretty simple. The high 57 bits are storage bits, and the lower 6 bits are "count" bits, which tells you how many of the storage bits actually store a contained value.



So far, I have a handful of very simple capabilities:



  1. An initializer that constructs empty bit vectors

  2. A count property of type Int

  3. An isEmpty property of type Bool

  4. An equality operator (==). NB: this is a value-equality operator akin to Object.equals() in Java, not a reference equality operator like == in Java.

I'm running into a bunch of cyclical dependancies:




  1. The unit test that tests my initializer need to verify that the newly constructed BitVector. It can do so in one of 3 ways:



    1. Check bv.count == 0

    2. Check bv.isEmpty == true

    3. Check that bv == knownEmptyBitVector

    Method 1 relies on count, method 2 relies on isEmpty (which itself relies on count, so there's no point using it), method 3 relies on ==. In any case, I can't test my initializer in isolation.



  2. The test for count needs to operate on something, which inevitably tests my initializer(s)


  3. The implementation of isEmpty relies on count


  4. The implementation of == relies on count.


I was able to partly solve this problem by introducing a private API that constructs a BitVector from an existing bit pattern (as a UInt64). This allowed me to initialize values without testing any other initializers, so that I could "boot strap" my way up.



For my unit tests to truly be unit tests, I find myself doing a bunch of hacks, which complicate my prod and test code substantially.



How exactly do you get around these sorts of issues?







unit-testing tdd swift-language






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jul 30 at 20:33









Jost

1033 bronze badges




1033 bronze badges










asked Jul 28 at 20:30









AlexanderAlexander

1,2128 silver badges16 bronze badges




1,2128 silver badges16 bronze badges










  • 20





    You are taking a too narrow view on the term "unit". BitVectoris a perfectly fine unit size for unit testing and immediately resolves your issues that public members of BitVector need each other to make meaningful tests.

    – Bart van Ingen Schenau
    Jul 29 at 9:09











  • You know too much implementation details up front. Is your development really test-driven?

    – herby
    Jul 30 at 20:44











  • @herby No, that's why I'm practicing. Although that seems like a really unattainable standard. I don't thing I've ever programmed anything without a pretty clear mental approximation of what the implementation will entail.

    – Alexander
    Jul 30 at 20:50











  • @Alexander You should try to relax that, otherwise it will be test-first, but not test-driven. Just say vague "I'll do a bit vector with one 64bit int as a backing store" and that's it; from that point on do TDD red-green-refactor one after another. Implementation details, as well as API, should emerge from trying to make tests run (the former), and from writing those tests in the first place (the latter).

    – herby
    Jul 30 at 20:54













  • 20





    You are taking a too narrow view on the term "unit". BitVectoris a perfectly fine unit size for unit testing and immediately resolves your issues that public members of BitVector need each other to make meaningful tests.

    – Bart van Ingen Schenau
    Jul 29 at 9:09











  • You know too much implementation details up front. Is your development really test-driven?

    – herby
    Jul 30 at 20:44











  • @herby No, that's why I'm practicing. Although that seems like a really unattainable standard. I don't thing I've ever programmed anything without a pretty clear mental approximation of what the implementation will entail.

    – Alexander
    Jul 30 at 20:50











  • @Alexander You should try to relax that, otherwise it will be test-first, but not test-driven. Just say vague "I'll do a bit vector with one 64bit int as a backing store" and that's it; from that point on do TDD red-green-refactor one after another. Implementation details, as well as API, should emerge from trying to make tests run (the former), and from writing those tests in the first place (the latter).

    – herby
    Jul 30 at 20:54








20




20





You are taking a too narrow view on the term "unit". BitVectoris a perfectly fine unit size for unit testing and immediately resolves your issues that public members of BitVector need each other to make meaningful tests.

– Bart van Ingen Schenau
Jul 29 at 9:09





You are taking a too narrow view on the term "unit". BitVectoris a perfectly fine unit size for unit testing and immediately resolves your issues that public members of BitVector need each other to make meaningful tests.

– Bart van Ingen Schenau
Jul 29 at 9:09













You know too much implementation details up front. Is your development really test-driven?

– herby
Jul 30 at 20:44





You know too much implementation details up front. Is your development really test-driven?

– herby
Jul 30 at 20:44













@herby No, that's why I'm practicing. Although that seems like a really unattainable standard. I don't thing I've ever programmed anything without a pretty clear mental approximation of what the implementation will entail.

– Alexander
Jul 30 at 20:50





@herby No, that's why I'm practicing. Although that seems like a really unattainable standard. I don't thing I've ever programmed anything without a pretty clear mental approximation of what the implementation will entail.

– Alexander
Jul 30 at 20:50













@Alexander You should try to relax that, otherwise it will be test-first, but not test-driven. Just say vague "I'll do a bit vector with one 64bit int as a backing store" and that's it; from that point on do TDD red-green-refactor one after another. Implementation details, as well as API, should emerge from trying to make tests run (the former), and from writing those tests in the first place (the latter).

– herby
Jul 30 at 20:54






@Alexander You should try to relax that, otherwise it will be test-first, but not test-driven. Just say vague "I'll do a bit vector with one 64bit int as a backing store" and that's it; from that point on do TDD red-green-refactor one after another. Implementation details, as well as API, should emerge from trying to make tests run (the former), and from writing those tests in the first place (the latter).

– herby
Jul 30 at 20:54











3 Answers
3






active

oldest

votes


















63














You're worrying about implementation details too much.



It doesn't matter that in your current implementation, isEmpty relies on count (or whatever other relationships you might have): all you should be caring about is the public interface. For example, you can have three tests:



  • That a newly initialized object has count == 0.

  • That a newly initialized object has isEmpty == true

  • That a newly initialized object equals the known empty object.

These are all valid tests, and become especially important if you ever decide to refactor the internals of your class so that isEmpty has a different implementation that doesn't rely on count - so long as your tests all still pass, you know you haven't regressed anything.



Similar stuff applies to your other points - remember to test the public interface, not your internal implementation. You may find TDD useful here, as you'd then be writing the tests you need for isEmpty before you'd written any implementation for it at all.






share|improve this answer






















  • 6





    @Alexander You sound like a man in need of a clear definition of unit testing. The best one I know comes from Michael Feathers

    – candied_orange
    Jul 29 at 1:16






  • 14





    @Alexander you are treating each method as an independently testable piece of code. That is the source of your difficulties. These difficulties disappear if you test the object as a whole, without trying to divide it into smaller parts. Dependencies between objects are not comparable with dependencies between methods.

    – amon
    Jul 29 at 7:36







  • 9





    @Alexander "a piece of code" is an arbitrary measurement. Just by initializing a variable you are using many "pieces of code." What matters is that you are testing a cohesive behavioural unit as defined by you.

    – Ant P
    Jul 29 at 8:40






  • 9





    "From what I've read, I got that the impression that if you break only piece of code, only unit tests directly relating to that code should fail." That seems to be a very hard rule to follow. (e.g. if you write a vector class, and you make an error on the index method, you will probably have tons of breakage across all the code that uses that vector class)

    – jhominal
    Jul 29 at 9:45






  • 4





    @Alexander Also, look into the "Arrange, Act, Assert" pattern for tests. Basically, you set up the object in whatever state it needs to be in (Arrange), call the method you're actually testing (Act) and then verify that its state changed according to your expectations. (Assert). Stuff you set up in Arrange would be "preconditions" for the test.

    – GalacticCowboy
    Jul 29 at 15:18



















5















How exactly do you get around these sorts of issues?




You revise your thinking on what a "unit test" is.



An object that manages a mutable data in memory is fundamentally a state machine. So any valuable use case is going to, at a minimum, invoke a method to put information into the object, and invoke a method to read a copy of information out of the object. In the interesting use cases, you are also going to be invoking additional methods that change the data structure.



In practice, this often looks like



// GIVEN
obj = new Object(...)

// THEN
assert object.read(...)


or



// GIVEN
obj = new Object(...)

// WHEN
object.change(...)

// THEN
assert object.read(...)


The "unit test" terminology -- well, it has a long history of not being very good.




I call them unit tests, but they don't match the accepted definition of unit tests very well -- Kent Beck, Test Driven Development by Example




Kent wrote the first version of SUnit in 1994, the port to JUnit was in 1998, the first draft of the TDD book was early 2002. The confusion had a lot of time to spread.



The key idea of these tests (more accurately called "programmer tests" or "developer tests") is that the tests are isolated from each other. The tests don't share any mutable data structures, so they can be run concurrently. There are no worries that the tests must be run in a specific order to correctly measure the solution.



The primary use case for these tests is that they are run by the programmer between edits to her own source code. If you are performing the red green refactor protocol, an unexpected RED always indicates a fault in your last edit; you revert that change, verify that the tests are GREEN, and try again. There isn't a lot of advantage in trying to invest in a design where each and every possible bug is caught by only one test.



Of course, is a merge introduces a fault, then finding that fault is no longer trivial. There are various steps you can take to ensure that faults are easy to localize. See



  • Parnas: On the criteria to be used in decomposing systems into modules

  • Rainsberger: Integrated tests are a scam

  • Shore: Testing Without Mocks: A Pattern Language





share|improve this answer
































    1














    In general (even if not using TDD) you should strive to write tests as much as possible while pretending you don't know how it is implemented.



    If you're actually doing TDD that should already be the case. Your tests are an executable specification of the program.



    How the call graph looks underneath the tests is irrelevant, as long as the tests themselves are sensible and well maintained.



    I think your problem is your understanding of TDD.



    Your problem in my opinion is that you are "mixing" your TDD personas. Your "test", "code", and "refactor" personas operate completely independently of each other, ideally.
    In particular your coding and refactoring personas have no obligations to the tests other than to make/keep them running green.



    Sure, in principle, it would be best if all tests were orthogonal and independent of each other. But that is not a concern of your other two TDD personas, and it is definitely not a strict or even necessarily realistic hard requirement of your tests. Basically: Don't throw out your common sense feelings about code quality to try to fulfill a requirement that nobody is asking of you.






    share|improve this answer



























      protected by gnat Jul 30 at 11:25



      Thank you for your interest in this question.
      Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).



      Would you like to answer one of these unanswered questions instead?














      3 Answers
      3






      active

      oldest

      votes








      3 Answers
      3






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      63














      You're worrying about implementation details too much.



      It doesn't matter that in your current implementation, isEmpty relies on count (or whatever other relationships you might have): all you should be caring about is the public interface. For example, you can have three tests:



      • That a newly initialized object has count == 0.

      • That a newly initialized object has isEmpty == true

      • That a newly initialized object equals the known empty object.

      These are all valid tests, and become especially important if you ever decide to refactor the internals of your class so that isEmpty has a different implementation that doesn't rely on count - so long as your tests all still pass, you know you haven't regressed anything.



      Similar stuff applies to your other points - remember to test the public interface, not your internal implementation. You may find TDD useful here, as you'd then be writing the tests you need for isEmpty before you'd written any implementation for it at all.






      share|improve this answer






















      • 6





        @Alexander You sound like a man in need of a clear definition of unit testing. The best one I know comes from Michael Feathers

        – candied_orange
        Jul 29 at 1:16






      • 14





        @Alexander you are treating each method as an independently testable piece of code. That is the source of your difficulties. These difficulties disappear if you test the object as a whole, without trying to divide it into smaller parts. Dependencies between objects are not comparable with dependencies between methods.

        – amon
        Jul 29 at 7:36







      • 9





        @Alexander "a piece of code" is an arbitrary measurement. Just by initializing a variable you are using many "pieces of code." What matters is that you are testing a cohesive behavioural unit as defined by you.

        – Ant P
        Jul 29 at 8:40






      • 9





        "From what I've read, I got that the impression that if you break only piece of code, only unit tests directly relating to that code should fail." That seems to be a very hard rule to follow. (e.g. if you write a vector class, and you make an error on the index method, you will probably have tons of breakage across all the code that uses that vector class)

        – jhominal
        Jul 29 at 9:45






      • 4





        @Alexander Also, look into the "Arrange, Act, Assert" pattern for tests. Basically, you set up the object in whatever state it needs to be in (Arrange), call the method you're actually testing (Act) and then verify that its state changed according to your expectations. (Assert). Stuff you set up in Arrange would be "preconditions" for the test.

        – GalacticCowboy
        Jul 29 at 15:18
















      63














      You're worrying about implementation details too much.



      It doesn't matter that in your current implementation, isEmpty relies on count (or whatever other relationships you might have): all you should be caring about is the public interface. For example, you can have three tests:



      • That a newly initialized object has count == 0.

      • That a newly initialized object has isEmpty == true

      • That a newly initialized object equals the known empty object.

      These are all valid tests, and become especially important if you ever decide to refactor the internals of your class so that isEmpty has a different implementation that doesn't rely on count - so long as your tests all still pass, you know you haven't regressed anything.



      Similar stuff applies to your other points - remember to test the public interface, not your internal implementation. You may find TDD useful here, as you'd then be writing the tests you need for isEmpty before you'd written any implementation for it at all.






      share|improve this answer






















      • 6





        @Alexander You sound like a man in need of a clear definition of unit testing. The best one I know comes from Michael Feathers

        – candied_orange
        Jul 29 at 1:16






      • 14





        @Alexander you are treating each method as an independently testable piece of code. That is the source of your difficulties. These difficulties disappear if you test the object as a whole, without trying to divide it into smaller parts. Dependencies between objects are not comparable with dependencies between methods.

        – amon
        Jul 29 at 7:36







      • 9





        @Alexander "a piece of code" is an arbitrary measurement. Just by initializing a variable you are using many "pieces of code." What matters is that you are testing a cohesive behavioural unit as defined by you.

        – Ant P
        Jul 29 at 8:40






      • 9





        "From what I've read, I got that the impression that if you break only piece of code, only unit tests directly relating to that code should fail." That seems to be a very hard rule to follow. (e.g. if you write a vector class, and you make an error on the index method, you will probably have tons of breakage across all the code that uses that vector class)

        – jhominal
        Jul 29 at 9:45






      • 4





        @Alexander Also, look into the "Arrange, Act, Assert" pattern for tests. Basically, you set up the object in whatever state it needs to be in (Arrange), call the method you're actually testing (Act) and then verify that its state changed according to your expectations. (Assert). Stuff you set up in Arrange would be "preconditions" for the test.

        – GalacticCowboy
        Jul 29 at 15:18














      63












      63








      63







      You're worrying about implementation details too much.



      It doesn't matter that in your current implementation, isEmpty relies on count (or whatever other relationships you might have): all you should be caring about is the public interface. For example, you can have three tests:



      • That a newly initialized object has count == 0.

      • That a newly initialized object has isEmpty == true

      • That a newly initialized object equals the known empty object.

      These are all valid tests, and become especially important if you ever decide to refactor the internals of your class so that isEmpty has a different implementation that doesn't rely on count - so long as your tests all still pass, you know you haven't regressed anything.



      Similar stuff applies to your other points - remember to test the public interface, not your internal implementation. You may find TDD useful here, as you'd then be writing the tests you need for isEmpty before you'd written any implementation for it at all.






      share|improve this answer















      You're worrying about implementation details too much.



      It doesn't matter that in your current implementation, isEmpty relies on count (or whatever other relationships you might have): all you should be caring about is the public interface. For example, you can have three tests:



      • That a newly initialized object has count == 0.

      • That a newly initialized object has isEmpty == true

      • That a newly initialized object equals the known empty object.

      These are all valid tests, and become especially important if you ever decide to refactor the internals of your class so that isEmpty has a different implementation that doesn't rely on count - so long as your tests all still pass, you know you haven't regressed anything.



      Similar stuff applies to your other points - remember to test the public interface, not your internal implementation. You may find TDD useful here, as you'd then be writing the tests you need for isEmpty before you'd written any implementation for it at all.







      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Jul 29 at 18:13

























      answered Jul 28 at 22:11









      Philip KendallPhilip Kendall

      7,3173 gold badges24 silver badges30 bronze badges




      7,3173 gold badges24 silver badges30 bronze badges










      • 6





        @Alexander You sound like a man in need of a clear definition of unit testing. The best one I know comes from Michael Feathers

        – candied_orange
        Jul 29 at 1:16






      • 14





        @Alexander you are treating each method as an independently testable piece of code. That is the source of your difficulties. These difficulties disappear if you test the object as a whole, without trying to divide it into smaller parts. Dependencies between objects are not comparable with dependencies between methods.

        – amon
        Jul 29 at 7:36







      • 9





        @Alexander "a piece of code" is an arbitrary measurement. Just by initializing a variable you are using many "pieces of code." What matters is that you are testing a cohesive behavioural unit as defined by you.

        – Ant P
        Jul 29 at 8:40






      • 9





        "From what I've read, I got that the impression that if you break only piece of code, only unit tests directly relating to that code should fail." That seems to be a very hard rule to follow. (e.g. if you write a vector class, and you make an error on the index method, you will probably have tons of breakage across all the code that uses that vector class)

        – jhominal
        Jul 29 at 9:45






      • 4





        @Alexander Also, look into the "Arrange, Act, Assert" pattern for tests. Basically, you set up the object in whatever state it needs to be in (Arrange), call the method you're actually testing (Act) and then verify that its state changed according to your expectations. (Assert). Stuff you set up in Arrange would be "preconditions" for the test.

        – GalacticCowboy
        Jul 29 at 15:18













      • 6





        @Alexander You sound like a man in need of a clear definition of unit testing. The best one I know comes from Michael Feathers

        – candied_orange
        Jul 29 at 1:16






      • 14





        @Alexander you are treating each method as an independently testable piece of code. That is the source of your difficulties. These difficulties disappear if you test the object as a whole, without trying to divide it into smaller parts. Dependencies between objects are not comparable with dependencies between methods.

        – amon
        Jul 29 at 7:36







      • 9





        @Alexander "a piece of code" is an arbitrary measurement. Just by initializing a variable you are using many "pieces of code." What matters is that you are testing a cohesive behavioural unit as defined by you.

        – Ant P
        Jul 29 at 8:40






      • 9





        "From what I've read, I got that the impression that if you break only piece of code, only unit tests directly relating to that code should fail." That seems to be a very hard rule to follow. (e.g. if you write a vector class, and you make an error on the index method, you will probably have tons of breakage across all the code that uses that vector class)

        – jhominal
        Jul 29 at 9:45






      • 4





        @Alexander Also, look into the "Arrange, Act, Assert" pattern for tests. Basically, you set up the object in whatever state it needs to be in (Arrange), call the method you're actually testing (Act) and then verify that its state changed according to your expectations. (Assert). Stuff you set up in Arrange would be "preconditions" for the test.

        – GalacticCowboy
        Jul 29 at 15:18








      6




      6





      @Alexander You sound like a man in need of a clear definition of unit testing. The best one I know comes from Michael Feathers

      – candied_orange
      Jul 29 at 1:16





      @Alexander You sound like a man in need of a clear definition of unit testing. The best one I know comes from Michael Feathers

      – candied_orange
      Jul 29 at 1:16




      14




      14





      @Alexander you are treating each method as an independently testable piece of code. That is the source of your difficulties. These difficulties disappear if you test the object as a whole, without trying to divide it into smaller parts. Dependencies between objects are not comparable with dependencies between methods.

      – amon
      Jul 29 at 7:36






      @Alexander you are treating each method as an independently testable piece of code. That is the source of your difficulties. These difficulties disappear if you test the object as a whole, without trying to divide it into smaller parts. Dependencies between objects are not comparable with dependencies between methods.

      – amon
      Jul 29 at 7:36





      9




      9





      @Alexander "a piece of code" is an arbitrary measurement. Just by initializing a variable you are using many "pieces of code." What matters is that you are testing a cohesive behavioural unit as defined by you.

      – Ant P
      Jul 29 at 8:40





      @Alexander "a piece of code" is an arbitrary measurement. Just by initializing a variable you are using many "pieces of code." What matters is that you are testing a cohesive behavioural unit as defined by you.

      – Ant P
      Jul 29 at 8:40




      9




      9





      "From what I've read, I got that the impression that if you break only piece of code, only unit tests directly relating to that code should fail." That seems to be a very hard rule to follow. (e.g. if you write a vector class, and you make an error on the index method, you will probably have tons of breakage across all the code that uses that vector class)

      – jhominal
      Jul 29 at 9:45





      "From what I've read, I got that the impression that if you break only piece of code, only unit tests directly relating to that code should fail." That seems to be a very hard rule to follow. (e.g. if you write a vector class, and you make an error on the index method, you will probably have tons of breakage across all the code that uses that vector class)

      – jhominal
      Jul 29 at 9:45




      4




      4





      @Alexander Also, look into the "Arrange, Act, Assert" pattern for tests. Basically, you set up the object in whatever state it needs to be in (Arrange), call the method you're actually testing (Act) and then verify that its state changed according to your expectations. (Assert). Stuff you set up in Arrange would be "preconditions" for the test.

      – GalacticCowboy
      Jul 29 at 15:18






      @Alexander Also, look into the "Arrange, Act, Assert" pattern for tests. Basically, you set up the object in whatever state it needs to be in (Arrange), call the method you're actually testing (Act) and then verify that its state changed according to your expectations. (Assert). Stuff you set up in Arrange would be "preconditions" for the test.

      – GalacticCowboy
      Jul 29 at 15:18














      5















      How exactly do you get around these sorts of issues?




      You revise your thinking on what a "unit test" is.



      An object that manages a mutable data in memory is fundamentally a state machine. So any valuable use case is going to, at a minimum, invoke a method to put information into the object, and invoke a method to read a copy of information out of the object. In the interesting use cases, you are also going to be invoking additional methods that change the data structure.



      In practice, this often looks like



      // GIVEN
      obj = new Object(...)

      // THEN
      assert object.read(...)


      or



      // GIVEN
      obj = new Object(...)

      // WHEN
      object.change(...)

      // THEN
      assert object.read(...)


      The "unit test" terminology -- well, it has a long history of not being very good.




      I call them unit tests, but they don't match the accepted definition of unit tests very well -- Kent Beck, Test Driven Development by Example




      Kent wrote the first version of SUnit in 1994, the port to JUnit was in 1998, the first draft of the TDD book was early 2002. The confusion had a lot of time to spread.



      The key idea of these tests (more accurately called "programmer tests" or "developer tests") is that the tests are isolated from each other. The tests don't share any mutable data structures, so they can be run concurrently. There are no worries that the tests must be run in a specific order to correctly measure the solution.



      The primary use case for these tests is that they are run by the programmer between edits to her own source code. If you are performing the red green refactor protocol, an unexpected RED always indicates a fault in your last edit; you revert that change, verify that the tests are GREEN, and try again. There isn't a lot of advantage in trying to invest in a design where each and every possible bug is caught by only one test.



      Of course, is a merge introduces a fault, then finding that fault is no longer trivial. There are various steps you can take to ensure that faults are easy to localize. See



      • Parnas: On the criteria to be used in decomposing systems into modules

      • Rainsberger: Integrated tests are a scam

      • Shore: Testing Without Mocks: A Pattern Language





      share|improve this answer





























        5















        How exactly do you get around these sorts of issues?




        You revise your thinking on what a "unit test" is.



        An object that manages a mutable data in memory is fundamentally a state machine. So any valuable use case is going to, at a minimum, invoke a method to put information into the object, and invoke a method to read a copy of information out of the object. In the interesting use cases, you are also going to be invoking additional methods that change the data structure.



        In practice, this often looks like



        // GIVEN
        obj = new Object(...)

        // THEN
        assert object.read(...)


        or



        // GIVEN
        obj = new Object(...)

        // WHEN
        object.change(...)

        // THEN
        assert object.read(...)


        The "unit test" terminology -- well, it has a long history of not being very good.




        I call them unit tests, but they don't match the accepted definition of unit tests very well -- Kent Beck, Test Driven Development by Example




        Kent wrote the first version of SUnit in 1994, the port to JUnit was in 1998, the first draft of the TDD book was early 2002. The confusion had a lot of time to spread.



        The key idea of these tests (more accurately called "programmer tests" or "developer tests") is that the tests are isolated from each other. The tests don't share any mutable data structures, so they can be run concurrently. There are no worries that the tests must be run in a specific order to correctly measure the solution.



        The primary use case for these tests is that they are run by the programmer between edits to her own source code. If you are performing the red green refactor protocol, an unexpected RED always indicates a fault in your last edit; you revert that change, verify that the tests are GREEN, and try again. There isn't a lot of advantage in trying to invest in a design where each and every possible bug is caught by only one test.



        Of course, is a merge introduces a fault, then finding that fault is no longer trivial. There are various steps you can take to ensure that faults are easy to localize. See



        • Parnas: On the criteria to be used in decomposing systems into modules

        • Rainsberger: Integrated tests are a scam

        • Shore: Testing Without Mocks: A Pattern Language





        share|improve this answer



























          5












          5








          5








          How exactly do you get around these sorts of issues?




          You revise your thinking on what a "unit test" is.



          An object that manages a mutable data in memory is fundamentally a state machine. So any valuable use case is going to, at a minimum, invoke a method to put information into the object, and invoke a method to read a copy of information out of the object. In the interesting use cases, you are also going to be invoking additional methods that change the data structure.



          In practice, this often looks like



          // GIVEN
          obj = new Object(...)

          // THEN
          assert object.read(...)


          or



          // GIVEN
          obj = new Object(...)

          // WHEN
          object.change(...)

          // THEN
          assert object.read(...)


          The "unit test" terminology -- well, it has a long history of not being very good.




          I call them unit tests, but they don't match the accepted definition of unit tests very well -- Kent Beck, Test Driven Development by Example




          Kent wrote the first version of SUnit in 1994, the port to JUnit was in 1998, the first draft of the TDD book was early 2002. The confusion had a lot of time to spread.



          The key idea of these tests (more accurately called "programmer tests" or "developer tests") is that the tests are isolated from each other. The tests don't share any mutable data structures, so they can be run concurrently. There are no worries that the tests must be run in a specific order to correctly measure the solution.



          The primary use case for these tests is that they are run by the programmer between edits to her own source code. If you are performing the red green refactor protocol, an unexpected RED always indicates a fault in your last edit; you revert that change, verify that the tests are GREEN, and try again. There isn't a lot of advantage in trying to invest in a design where each and every possible bug is caught by only one test.



          Of course, is a merge introduces a fault, then finding that fault is no longer trivial. There are various steps you can take to ensure that faults are easy to localize. See



          • Parnas: On the criteria to be used in decomposing systems into modules

          • Rainsberger: Integrated tests are a scam

          • Shore: Testing Without Mocks: A Pattern Language





          share|improve this answer














          How exactly do you get around these sorts of issues?




          You revise your thinking on what a "unit test" is.



          An object that manages a mutable data in memory is fundamentally a state machine. So any valuable use case is going to, at a minimum, invoke a method to put information into the object, and invoke a method to read a copy of information out of the object. In the interesting use cases, you are also going to be invoking additional methods that change the data structure.



          In practice, this often looks like



          // GIVEN
          obj = new Object(...)

          // THEN
          assert object.read(...)


          or



          // GIVEN
          obj = new Object(...)

          // WHEN
          object.change(...)

          // THEN
          assert object.read(...)


          The "unit test" terminology -- well, it has a long history of not being very good.




          I call them unit tests, but they don't match the accepted definition of unit tests very well -- Kent Beck, Test Driven Development by Example




          Kent wrote the first version of SUnit in 1994, the port to JUnit was in 1998, the first draft of the TDD book was early 2002. The confusion had a lot of time to spread.



          The key idea of these tests (more accurately called "programmer tests" or "developer tests") is that the tests are isolated from each other. The tests don't share any mutable data structures, so they can be run concurrently. There are no worries that the tests must be run in a specific order to correctly measure the solution.



          The primary use case for these tests is that they are run by the programmer between edits to her own source code. If you are performing the red green refactor protocol, an unexpected RED always indicates a fault in your last edit; you revert that change, verify that the tests are GREEN, and try again. There isn't a lot of advantage in trying to invest in a design where each and every possible bug is caught by only one test.



          Of course, is a merge introduces a fault, then finding that fault is no longer trivial. There are various steps you can take to ensure that faults are easy to localize. See



          • Parnas: On the criteria to be used in decomposing systems into modules

          • Rainsberger: Integrated tests are a scam

          • Shore: Testing Without Mocks: A Pattern Language






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Jul 29 at 12:22









          VoiceOfUnreasonVoiceOfUnreason

          20k1 gold badge27 silver badges51 bronze badges




          20k1 gold badge27 silver badges51 bronze badges
























              1














              In general (even if not using TDD) you should strive to write tests as much as possible while pretending you don't know how it is implemented.



              If you're actually doing TDD that should already be the case. Your tests are an executable specification of the program.



              How the call graph looks underneath the tests is irrelevant, as long as the tests themselves are sensible and well maintained.



              I think your problem is your understanding of TDD.



              Your problem in my opinion is that you are "mixing" your TDD personas. Your "test", "code", and "refactor" personas operate completely independently of each other, ideally.
              In particular your coding and refactoring personas have no obligations to the tests other than to make/keep them running green.



              Sure, in principle, it would be best if all tests were orthogonal and independent of each other. But that is not a concern of your other two TDD personas, and it is definitely not a strict or even necessarily realistic hard requirement of your tests. Basically: Don't throw out your common sense feelings about code quality to try to fulfill a requirement that nobody is asking of you.






              share|improve this answer































                1














                In general (even if not using TDD) you should strive to write tests as much as possible while pretending you don't know how it is implemented.



                If you're actually doing TDD that should already be the case. Your tests are an executable specification of the program.



                How the call graph looks underneath the tests is irrelevant, as long as the tests themselves are sensible and well maintained.



                I think your problem is your understanding of TDD.



                Your problem in my opinion is that you are "mixing" your TDD personas. Your "test", "code", and "refactor" personas operate completely independently of each other, ideally.
                In particular your coding and refactoring personas have no obligations to the tests other than to make/keep them running green.



                Sure, in principle, it would be best if all tests were orthogonal and independent of each other. But that is not a concern of your other two TDD personas, and it is definitely not a strict or even necessarily realistic hard requirement of your tests. Basically: Don't throw out your common sense feelings about code quality to try to fulfill a requirement that nobody is asking of you.






                share|improve this answer





























                  1












                  1








                  1







                  In general (even if not using TDD) you should strive to write tests as much as possible while pretending you don't know how it is implemented.



                  If you're actually doing TDD that should already be the case. Your tests are an executable specification of the program.



                  How the call graph looks underneath the tests is irrelevant, as long as the tests themselves are sensible and well maintained.



                  I think your problem is your understanding of TDD.



                  Your problem in my opinion is that you are "mixing" your TDD personas. Your "test", "code", and "refactor" personas operate completely independently of each other, ideally.
                  In particular your coding and refactoring personas have no obligations to the tests other than to make/keep them running green.



                  Sure, in principle, it would be best if all tests were orthogonal and independent of each other. But that is not a concern of your other two TDD personas, and it is definitely not a strict or even necessarily realistic hard requirement of your tests. Basically: Don't throw out your common sense feelings about code quality to try to fulfill a requirement that nobody is asking of you.






                  share|improve this answer















                  In general (even if not using TDD) you should strive to write tests as much as possible while pretending you don't know how it is implemented.



                  If you're actually doing TDD that should already be the case. Your tests are an executable specification of the program.



                  How the call graph looks underneath the tests is irrelevant, as long as the tests themselves are sensible and well maintained.



                  I think your problem is your understanding of TDD.



                  Your problem in my opinion is that you are "mixing" your TDD personas. Your "test", "code", and "refactor" personas operate completely independently of each other, ideally.
                  In particular your coding and refactoring personas have no obligations to the tests other than to make/keep them running green.



                  Sure, in principle, it would be best if all tests were orthogonal and independent of each other. But that is not a concern of your other two TDD personas, and it is definitely not a strict or even necessarily realistic hard requirement of your tests. Basically: Don't throw out your common sense feelings about code quality to try to fulfill a requirement that nobody is asking of you.







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Aug 2 at 21:10

























                  answered Jul 30 at 6:46









                  Tim SeguineTim Seguine

                  1177 bronze badges




                  1177 bronze badges


















                      protected by gnat Jul 30 at 11:25



                      Thank you for your interest in this question.
                      Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).



                      Would you like to answer one of these unanswered questions instead?



                      Popular posts from this blog

                      Grendel Contents Story Scholarship Depictions Notes References Navigation menu10.1093/notesj/gjn112Berserkeree

                      Area configuration aggregation error after install Porto themeMagento 2.1 CE Installed but front/backend not loading/workingCSS not loading on page within Magento 2 pageCannot install module in Magento 2no commands defined in the “setup” namespace. in Magento2Magento 2: Static files are present but shows 404Why do i have to always run the commands to clean cache in Magento 2.1.8?Failure reason: 'Unable to unserialize value.'Error 500 after magento migrationIn production mode the site does not loadMagento 2 : Error 500 after installing

                      Middle Expansion Olielle Resaix Definition: Uttering songs of triumph shouting with joy triumphant exulting Sejunction Journal 붙다 달 고급 품목 외출 The stretch trades the screeching tin. Definition: The act of speaking with a drawl a drawl Cough Sand Definition: An uproar a quarrel a noisy outbreak Shake Iron Publicize Horse House Baby 사과 Resaix Flaggy Jelly Temporary Unequaled Puppet A drop in the bucket Shrew 성격 회원 성질 미팅 The burn frames the tacky quality. Materialistic The smoke reduces the way. Yammoe Nondescript Cheek 얼굴 배 약하다 날리다 타다 The illegal country shows the iron. Help Rule Drearien Smoke Teaching Meaty Wasp Abraham Lincoln Jaws 진심 수리하다 Size Cork Idea Convert Think Lark John Lennon 거울 청소 군 추천하다 아이스크림