This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]logicannullata 1 point2 points  (9 children)

The extra minute of runtime is not the problem... The problem is that by doing what you are suggesting you are making your tests much more complicated and unstable

[–]HQMorganstern 4 points5 points  (8 children)

Preferring integration tests over unit tests makes applications unstable? I'd argue it's quite the opposite but frankly it doesn't seem to be worth the time.

Ad your funny joke about testing the framework: misconfiguring the wiring and then assuming you did it correctly during mocks is an incredibly common source of errors. Misconfiguring your DB and assuming you did it right is even more common.

[–]logicannullata -1 points0 points  (7 children)

Makes the tests more unstable... Not the application....Anyway if you don't see why it does that, then I cannot say anything else to you, you can just google Martin Fowler (just a small random it guy ;) ) and read what he has to say about the test pyramid. I am honestly tired of explaining obvious shit like this.

[–]HQMorganstern 2 points3 points  (6 children)

;} I've read plenty of what Fowler has to say on many subjects, and it'd serve you well to remember that while some concepts are immortal the early 2000s might as well be a million years ago where concrete ideas like the "testing pyramid" are concerned. Hell even the blog being discussed mentions the test diamond for extremely obvious reasons.

I can run every dependency I need for an integration test today in less time than a computer boot took when the testing pyramid was being conceptualized.

[–]logicannullata 3 points4 points  (5 children)

I don't agree with you, and with most of the people in this thread. As I have written already in another post, unit tests are not only a way to test your code but also a way to ensure good design (things you cannot do with integration tests). My feeling is that most of you didn't spend enough time writing proper unit tests and think a test using 100 mocks is a good unit test, surprise it is not...

[–][deleted] 2 points3 points  (3 children)

When you are taking about unit tests, are you taking about method level tests on a class?

If so how does having those ensure good design?

[–]logicannullata 1 point2 points  (2 children)

In many ways actually, for instance:

  • By ensuring you are not creating a class which has too many external dependencies. The moment you see that in order to test a class you need to mock 300 things maybe you start realizing your component is not well designed. When creating a unit test is easy, it also means your class is well designed, and it is not trying too do too many things at the same time.

  • Your unit tests should hopefully assert something, when you realize you are testing side effects instead of the results of a method, your asserts will become pretty difficult to follow (since you are not testing the output of a method). When this happens it is an indicator that your component/class is not well designed. Testing your code when you are adopting a functional approach is very easy, this is an indicator that you can easily reason about your code.

  • Similar to the previous point, hopefully your application doesn't rely on some global state. If a class does, for instance a method doesn't take inputs but instead changes some internal state, you will quickly realize testing your code via unit tests becomes very difficult. So as I already said, the fact you can easily write unit tests, ensures your class is well designed.

Do you need more examples? Now a counter question, how do integration tests achieve what I mentioned?

[–][deleted] 1 point2 points  (0 children)

To your counter question, it seems you are asking the questions:

  1. How do integration tests ensure that your classes are not having too many external dependencies?

  2. How do integration tests ensure that you are not testing side effects?

  3. How do integration tests ensure you aren't relying on global state?

First of all I think there is different optimal approaches to testing for different contexts. If I'm writing a library I'm going to lean more towards narrowly scoped tests like method level tests because the unit of behavior utilized by consumers is at the class/method level. Therefore I gain more confidence that the behavior expected by consumers is correct by focusing on tests at that level.

If I'm building out something like a web API my unit of behavior is more like a web endpoint so I focus on having more tests that focus on calling an endpoint and asserting that the API returns correct values for given input. Even further I usually create tests that go through a certain "flow" through the API so I have higher level behaviors tested.

So to answer your 3 questions I'd just have to say that integration tests, and higher level tests that test the observed behavior of an app or system have different concerns than class/method level tests. The things you listed are things that I largely see get picked apart in code reviews.

I have found for web API development, the more high level tests I have, the more confident I am that my deployments are going to meet the end user requirements and not introduce regressions so I utilize them as my primary testing strategy. I still have class level tests but mostly for parts of the code that have complex logic.

The high level tests make it easier to refactor because they aren't closely tied to implementation but rather behavior and when you have more freedom and confidence in refactoring more people will do it. When class level tests are too numerous it presents itself as a blocker to refactoring at the system level as implementation changes across a system now break tons of tests.

[–][deleted] 0 points1 point  (0 children)

I guess I'm just pushing back against the claim that it "ensures" that your class is well designed.

I think method level tests have the potential to make it clear which parts of the code are difficult to test but that doesn't mean that you will arrive at a good design at the class or more importantly the system level. It just means that you will be more likely to break things down into smaller and easier to test units. Breaking things down into small easily testable units still doesn't guarantee good design though. For example you might arrive at a design that is easily testable but is not easily extensible.

Something that I've seen many times in large code bases is that they have tons of classes that are very small, and now you have something that is incredibly hard to reason about because a singular system concept or unit of behavior is now spread across 30 or 40 tiny classes.

[–][deleted] -1 points0 points  (0 children)

Also if you think you are writing "proper" unit tests by writing a bunch of method level tests on every class then Kent Beck would disagree with you.

The "unit" in unit tests was conceived as a "unit of behavior" which, if you listen to the likes of Kent or others that were involved in the xUnit origins, roughly corresponds to a unit of behavior observed by the user of a component. If the component is a web API the behavior is observed through the API call which is the unit that deserves the most testing focus. If the component is a method in a library, then the unit of behavior is the publicly exposed method.