3 ms·
> because in a language like Python there is no such thing as > information hiding and coupled with dynamic typing, it > means that your tests end up tightl
by rimliu 10y ago
> because in a language like Python there is no such thing as
> information hiding and coupled with dynamic typing, it
> means that your tests end up tightly coupled with
> implementation details, will break on correct refactoring
> and will be hard to fix.
Would you mind to provide more details about this point? I thought dynamic languages make testing easier, because you don't care about the type of the object as long as it works with the same API (if it quacks…).
This also supposedly makes it way easier to mock objects. Now there you are basically claiming (unless I misunderstand your claims) the opposite.
- zephyrfalcon 10y agoYou are correct. The problem here seems to be that the OP's tests depend on implementation details, which of course shouldn't happen. Presumably this wouldn't occur in a language where you could hide these implementation details (private attributes/methods, etc). That said, Python doesn't force you or encourage you to write your tests like this. Just because it's possible to access the implementation, doesn't mean you should.
- NateDad 10y agoTests always rely on implementation details. The implementation details are what you're testing, after all. The problem is relying on the wrong ones. You can hide all the details you want in the language, unless it's a pure function, there's side effects that can be relied on improperly. Often times this is because of hiding implementation details. A GenerateCert function might read from a config file. It hides the detail that the config file exists, but then to test it you need to create the file in the right spot. Yes, testing Add(int, int) is easy in any language. No one's struggling with those tests.
- 46Bit 10y ago"Dynamic languages make testing easier," paints a very broad brush. They have some very nice benefits, but also a lot of edgecases. * An argument might be an int when you expected a float. This can be addressed by casting things with `float()` in every entrypoint, but it's more defensive to require a float and error out otherwise. Either way, problems only appear at runtime. * An object might be null and this only gets picked up at runtime - using Rust it's been very nice to have to explicitly say when things can be null. I've found it can feel like luck when a complex Python program works correctly for real-world input, but it's also very powerful at getting something done. Tradeoffs.
- btschaegg 10y ago> An object might be null and this only gets picked up at runtime - using Rust it's been very nice to have to explicitly say when things can be null. This point actually frustrates me greatly about C# 7. At some point, there was talk about non-nullable references being introduced into the language, which has been put on hold for at least another version. Personally, I think that feature should have been in the language since version 1. Every runtime error due to a null reference is one too many.
- DenisM 10y agoI have thought about creating a template struct with a single member that blows up if you try to insert null. Something like this: public struct NotNull<T> { private readonly T val; public T Value { get { return val; } } public NotNull(T v) { if (v==null) throw new Exception(); val = v; } } However you can still create a class FOO with a member NotNull<T> xxx and xxx may be entirely uninitialized. It can be then passed from one method to another until you try to read it, so it basically does not give any guarantees. I thinks this is why they pulled non-nullable types from C# - they couldn't figure out what to do in this case. If I were them I would force the constructor of FOO to blow up on exit if xxx is not populated. That would help a little bit. Although it still causes problems if a method is invoked from the constructor. So yeah, it's a tough problem. Maybe they could add a check when a field of type NotNull<T> is read to throw an exception? That way you're still possibly in trouble when reading a field, but at least you can be confident that if you receive a method parameter NotNull<T> you know it's not null.
- btschaegg 10y agoI also thought about solutions like this for a while, but frankly, every option sounds like the attempt to fix a leaking dam using duct tape. Things like this have to be implemented properly. The problem is that this ties into the core architecture of the platform, not only the language - references are basically the most important implicit primitive there is in the CLR (implicit because not even the IL handles them like the other datatypes). I'm not very informed on the subject, but I suspect that without a proper way to declare locals and members non-nullable in the CLR, the matter would get rather complicated - there'd be no possibility to communicate the requirement through method signatures, for example. And since you could call pretty much any C# method from other languages, I'd expect various problems there. Of course, one option would be to only handle the initialization and assignment checks in the C# compiler (I guess that would be much easier) and simply generate conditional ArgumentNullExceptions in every method, but I suspect that this would be a problem for performance reasons.
- always_good 10y agoThat's simply more precarious than making an anonymous object that adheres to a statically-enforced protocol.