Re: Unit Testing Frameworks (was Re: Singletons)
On 1/8/2013 7:25 PM, Tobias M??ller wrote:
???? Tiib <ootiib@hot.ee> wrote:
It has been several times asked in this thread: Why it is difficult to
create fake Singleton::instance() that is instrumented to return an
mock object that you want? Usual answer has been repeated "clear and
obvious" fact that DI is somehow simpler. Ok, but why and how?
Usually, you test the external interface of a class if it behaves the way
it has to. The use of a singleton in the class is an implementation detail
and may thus easily be forgotten to test.
With DI, you the "singleton" is part of the public interface of the class
and can be tested without making assumptions on the internals of the class.
That sounds like a very good argument *against* DI.
You stated that use of the singleton was a detail of implementation
only. After the refactoring (hm, doe that still count as refactoring?)
you have it in the public interface. Where it should not appear if we
map the abstract design correctly.
For many singletons we deliberately don't test state, they are only
needed to allow the tested stuff work. For those actually involved with
testing mus have required change attached. What is hard to forget due to
that requirement being present. IMO it's a pretty lousy idea to mess up
an interface out of fear that someone forgets to read reqs doing
implementation, review and other testing. There must be better tools
present.
With DI you have to specify an interface for those "singletons" that may be
injected, with a real singleton one is tempted to just create, use and
modify it ad hoc. A well defined interface is always good for testing.
I'd be interested in criteria for 'well designed' interface here. As
implementation-only stuff leaking to public portion for me indicates bad
one. And for general testability we already concluded that there's no
practical difference in favor of DI (those still keeping the opposite
opinion, please present some new case with difference or point out
mistakes in reasoning upthread).
Of course you can replace a singleton with a mock if you really want to.
But you cannot just take you library and build a test application around
it.
How so? It is one of the popular approaches. (Unless you mean a
mandatory 1-1 mapping, after some size you build multiple executables.)
You have to exclude the complete singleton implementation from the
original code and replace it with a different one.
Sure, if the original is not fit, and you go for a mock, you leave out
the original or reroute the code to the same effect. That is hardly a
problem.
In practice that means you have to replace some source files with others
just for testing.
The usual way is the opposite one, you drag one source file for testing,
or a few.
You cannot use the original binary to build your tests
around it, but have to compile (at least link) everything again.
Hm? If we talk about a traditional static library, all you need is to
pack the implementation of the singleton in a separate object file.
Define your own version and link with the lib -- and it is left unlinked.
Possibly even with different compiler settings.
But building the *unit* test suit separately is pretty common. Different
settings are no problem either.
While testing the image that you will deploy happens on different level,
where details about internal object passing are not seen in the first place.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]