4 ms·
Here's the thing. You're not going to forgo your tests, right? But testing in a statically typed language is much harder to get right. But you still need them.
by nickbauman 11y ago
Here's the thing. You're not going to forgo your tests, right? But testing in a statically typed language is much harder to get right. But you still need them. So the question of static or dynamic typing is moot.
- chadaustin 11y agoWhy is testing harder in a statically typed language? Seems about the same to me.
- phamilton 11y agoMonkey patching is often difficult in a statically types language, but is quite useful in testing.
- chadaustin 11y agoAh, fair enough! Though monkey patching is only possible in some dynamic languages, namely the ones where classes and modules are mutable hash tables. Note that in ES6, unless you insert some special code via something like babel-rewire, imports can't be monkey patched. Also, Scheme is dynamically-typed and has no monkey patching. Anyway, I agree monkey patching in tests can be pretty convenient! But I personally think it's also a bad idea because it means that your tests are now coupled to the internal implementation of the code under test. That is, if you refactored the implementation, the test could break. Passing testable dependencies explicitly avoids this problem and avoids the need to monkey patch in tests.
- phamilton 11y agoThat seems like more of an argument against mocking in general. Even if you DI you are still expecting X method to be called on the mock object and have created that coupling. I think DHH describes a great example that illustrates a big difference in philosophy around this: http://david.heinemeierhansson.com/2012/dependency-injection-is-not-a-virtue.html http://david.heinemeierhansson.com/2012/dependency-injection...
- nrinaudo 11y agoWhile I see your point, if you ever find yourself wishing for monkey patching while writing a test in a statically typed language, it's a code smell. You've not abstracted things enough. If you need to modify things that way but can't, you should consider abstracting over it and making it possible at runtime. That way, not only do you get to write a better test - a whole class of errors is gone, just not possible anymore - you also have a more modular system, the components of which you can test individually.
- phamilton 11y agoDHH captures this very well http://david.heinemeierhansson.com/2012/dependency-injection-is-not-a-virtue.html http://david.heinemeierhansson.com/2012/dependency-injection... I think his example of system time is a good one because an abstraction in that case often only serves to enable testing. If testing is already possible, then that abstraction is just unneeded complexity
- nrinaudo 11y agoWithout any sarcasm of any kind, I expect I must be missing the point of what you linked and would love for you to clarify it. What I understood was, changing the way time is handled for your entire Ruby process in order to test that some publish function sets the right date is good practice. As opposed to, say, have it expect a date argument, which lets you test it without side effects that can impact absolutely everything else, and gets you a more powerful feature, publishAt rather than just publishNow. If I understood this correctly (which I honestly doubt), I don't think our conversation serves much purpose. You seem to regard as good practice what I consider utter lunacy. I don't pretend that I'm right, just that there's absolutely no chance that we'll agree on this. That being said, your point about introducing abstraction for the sole purpose of enabling tests is well made. My experience is that you'll often end up glad you abstracted over whatever it was you needed for the tests and use it in live code, but not 100% of the time. But if the alternative is global mutable states, I'll consider un-needed abstraction the lesser of two evils and gladly embrace it.
- 11y ago
- nickbauman 11y agoOne of the biggest benefits of testing comes from writing the test prior to the implementation (TDD). In a statically typed language, your test won't compile until the implementation is there, meaning this process is less accessible to you. Type systems focus on making sure you write the code correctly. They help not at all whether you're writing the correct code. In the end, this is on you, the developer, to express correctness in the type system. So the theory goes if you can define the problem correctly in, say, Haskel's type system, (up front, mind you), you may not even need any tests. But most systems are built with incomplete information. You can't know everything ahead of time. Often what is ultimately "correct" is to ship sooner rather than later, learning what is systemically correct as you go along. This is where dynamic languages do well.
- dllthomas 11y ago> But most systems are built with incomplete information. You can't know everything ahead of time. Often what is ultimately "correct" is to ship sooner rather than later, learning what is systemically correct as you go along. This is where dynamic languages do well. Again, my experience is that this is precisely where the type checker gives me the most help.
- chadaustin 11y agoWell, I've done lots of TDD in both Python/PHP/JS _and_ Haskell and C++, and I don't agree at all. I was the advocate for TDD at IMVU and built many of the test frameworks and core systems across all languages. You can definitely TDD Haskell, for example, with liberal use of "undefined" or "error". Same with C++: just throw an exception in code paths you haven't "explored" with tests yet. Also, the notion that because Haskell has a strong type system you don't need tests is a persistent myth. It's nice to have types to prove certain aspects of your program, but you still need a test suite in any significant project.
- dllthomas 11y ago> Also, the notion that because Haskell has a strong type system you don't need tests is a persistent myth. It's nice to have types to prove certain aspects of your program, but you still need a test suite in any significant project. I think that given a strong type system there exist tests you might otherwise write that you don't need. And I think that is sometimes confused for "given a strong type system, all tests are unnecessary" (which, in my opinion/experience, certainly does not hold), both by some people advocating type systems and by some people reacting to advocacy of type systems.
- nrinaudo 11y agoI don't understand how this is harder in a statically typed language. The only explanation I can think of is that the type system makes it harder to write incorrect tests by refusing anything that doesn't make sense, from a type point of view. This can be frustrating, but the only reason it feels easier in a dynamic language is that the compiler lets you get away wih more. It's easier to write incorrect tests. I hardly think this is a good selling point.
- lmm 11y agoI am going to forego a lot of tests yes. A lot of tests become irrelevant with the right types. See https://spin.atomicobject.com/2014/12/09/typed-language-tdd-part1/ https://spin.atomicobject.com/2014/12/09/typed-language-tdd-... (and part 2) for a good example (and note that the example deliberately uses the worst type system around at the time, Java - you can write the typed versions much more efficiently in most languages).