3 ms·
If you need lots of mocks, it's a sign of coupling which means a bad fundamental design. You need to test both the components individually (unit tests) and the
by meaty 14y ago
If you need lots of mocks, it's a sign of coupling which means a bad fundamental design.
You need to test both the components individually (unit tests) and their interaction (integration tests).
We use Commons VFS for filesystem abstraction ( http://commons.apache.org/vfs/ http://commons.apache.org/vfs/ ) and our own port of the API for .Net.
In fact we have our own systems API (more Google AppEngine style thank say the .Net Framework or Java libraries) on which we build our software.
- jiggy2011 14y agoThat may be true, but sometimes it can also be a pain when you are talking to everything through a load of abstraction layers. When something blows up it can be nice just to get a simple error rather than a 20 page stack trace.
- Silhouette 14y agoThat may be true, but sometimes it can also be a pain when you are talking to everything through a load of abstraction layers. Exactly. Sometimes the benefit of a certain kind of test does not outweigh the cost of distorting a useful design so it will support the test code. That cost might be directly in terms of performance overhead, or it can be a more subtle overhead through (for example) weakening language-enforced modularity in your architecture so you can insert mock/stub placeholders where you want them for testing purposes, which can hurt everything from maintenance overheads to the effectiveness of code reviews.
- jiggy2011 14y agoI think dependency injection is designed to mostly solve that problem but with that you want to program in a very specific way (e.g calling the DI framework's factory methods rather than just using "new" and a constructor method). This makes it more difficult to retrofit to code and is sort of awkward when you are integrating with different bits of code and libraries that don't use DI. Thus the usefulness of mocking frameworks to "force" a particular class to be a certain implementation for the purposes of testing.
- meaty 14y agoHint: You never have to distort a design for testing, if it's not a crock. It's a great indicator of brokeness.
- Silhouette 14y agoThat's not a hint, it's a conceit, born in the kind of fantasy world that drinks whatever folks like Bob Martin are selling and loves names like SimpleBeanFactoryAwareAspectInstanceFactory and functions no more than five lines long. In the real world, software architecture is the servant of many masters, often including multiple kinds of testing, and sometimes you can't do everything that each of them would like all at the same time. For a start, they can be objectively contradictory: every time you add a dedicated test hook or introduce inversion of control to support unit testing, for example, you have also created additional cases that need to be considered during a code review. However, it's important to remember that all these testing methods and design techniques are merely means to an end. They are valuable precisely to the extent that they help us build software to do useful things, and no more. If they sometimes conflict, that's OK, as long as we favour the one that most helps us to get the job done. However, things tend to go wrong if we start nerfing one aspect just because dogma says we must not compromise on another.
- meaty 14y agoA 20 page stack trace is the symptom of another problem, not a result of decoupling.
- jiggy2011 14y agoTrue, but the most popular method of decoupling seems to be via using an abstraction layer of some kind. At some point you need to talk to a concrete "thing". It's also difficult to know ahead of time how much abstraction is the right amount ahead of time. For example, you abstract disk access through an RDBMS but you might want to change DBMS so you abstract that through an ORM. But maybe you want to switch away from RDBMS altogether and go with a NoSQL solution or do everything with message queues or REST APIs? Should you abstract up another level also?
- meaty 14y agoThat's vertical decoupling. Well the point of the abstraction is that you don't care about the contents, hence the term "black box abstraction". It doesn't matter to the interface consumer what the implementation is, just that it does what the interface says it will do. Our VFS layer has various backends which can be picked based on the client's requirements and this covers REST APIs, RDBMS and filesystems. There are various depths of stacks and abstractions hiding behind all that but to the consumer, it doesn't matter. If it blows up anywhere in the stack, we can throw 80 levels of stack right down to the container thread if need be, but we only care about the abstraction at the point of failure.