Let's say I have the following class:
class foo {
public:
foo();
void addItem(int item);
private:
int* items;
};
I want to write a unit test program to test foo::addItem(), to do that
the test program needs to know the contents of foo::items.
So I can add one more public function to class foo:
int* getItems();
But suppose in my case, the client code of class foo does not need
getItems() at all, this function serves only for test in this case.
So I am considering to have a separate class fooTest and this class is
a friend class of class foo so that it has an API to retrieve all
private data of foo.
I believe this works, but I am wondering if there is better solution.
Basically my goals are:
1. I do not want the class to be bloated with a lot of API which only
serve for test purpose
2. I want the function class to be independent from test class
Thanks a lot.
> Let's say I have the following class:
>
> class foo {
> public:
> foo();
> void addItem(int item);
>
> private:
> int* items;
>
> };
>
> I want to write a unit test program to test foo::addItem(), to do that
> the test program needs to know the contents of foo::items.
"Testing privates" is a FAQ in the unit testing communities.
The best answers is: If you invented your class using Test Driven Development,
then foo would expose enough effects of its private member - slightly more
effects than its production clients need - that tests can indirectly assess the
performance of the private.
This strategy leverages the purpose of privacy - you can migrate int * items to
some other system (such as std::vector<int> items!), without changing any tests.
More below.
> So I can add one more public function to class foo:
> int* getItems();
>
> But suppose in my case, the client code of class foo does not need
> getItems() at all, this function serves only for test in this case.
>
> So I am considering to have a separate class fooTest and this class is
> a friend class of class foo so that it has an API to retrieve all
> private data of foo.
>
> I believe this works, but I am wondering if there is better solution.
> Basically my goals are:
> 1. I do not want the class to be bloated with a lot of API which only
> serve for test purpose
> 2. I want the function class to be independent from test class
To add unit tests to pre-existing, Read /Working Effectively with Legacy Code/
by Mike Feathers. He will probably not mention the most savage hack possible in C++:
#define private public
If you cleanly recompile all your modules in that mode (such as modules going
into a special "test mode" binaries folder), you can safely write unit tests
that see any private. Make sure not to put that line above any #include that
pulls in something you can't recompile in that mode, such as a standard library
module.
--
Phlip
> private:
> int* items;
> };
The solution in C++ is to use type coercion. The basic concept is to
produce an exact like-for-like representation of the target type, but with
read-only access to the rep.
type FooREP
{
public:
const int* items() const { return items ; }
private:
int* items ;
} ;
Foo f ;
FooREP* rep = static_cast<FooREP* >( &f) ;
Now you have access to the internal representation of a Foo.
IMHO the best approach (in terms of increased correctness, testability,
reusability etc) is to define the getItems op, and then define (in terms
of getItems) a 'difference' post-condition for addItems.
The primary reason for this is : having access to the rep is pointless if
you don't know what the rep state is at the begin/end of each op. And
if you do know, then tis better to explicitly state that knowledge in
post/invariant conditions (ie ADT REP conditions) .
If you had prog lang support for Design by Contract, you could make the
REP conditions private too (ie they are hidden from the user) .
Regards,
Steven Perryman
> So I am considering to have a separate class fooTest and this class is
> a friend class of class foo so that it has an API to retrieve all
> private data of foo.
This is pretty standard in C++. In fact, test harnesses are the only
thing I would ever use 'friend' for.
--
There is nothing wrong with me that could
not be cured by a capful of Drano.
H. S. Lahman
h...@pathfindermda.com
Pathfinder Solutions
http://www.pathfindermda.com
blog: http://pathfinderpeople.blogs.com/hslahman
"Model-Based Translation: The Next Step in Agile Development". Email
in...@pathfindermda.com for your copy.
Pathfinder is hiring:
http://www.pathfindermda.com/about_us/careers_pos3.php.
(888)OOA-PATH
[...]
> "Testing privates" is a FAQ in the unit testing communities.
> The best answers is: If you invented your class using Test
> Driven Development, then foo would expose enough effects of
> its private member - slightly more effects than its production
> clients need - that tests can indirectly assess the
> performance of the private.
Actually, I think that test driven development would have a
slightly negative effect here. Greg made the real point: a
function has post-conditions. If you can't see them, then they
don't matter, and so aren't real post-conditions. And if you
can see them, you verify that they work.
But this concept really comes out of programming by contract,
rather than test driven design (which can easily be used to
avoid specifying the necessary contracts).
--
James Kanze (GABI Software) email:james...@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
> Hi,
>
> Let's say I have the following class:
>
> class foo {
> public:
> foo();
> void addItem(int item);
>
> private:
> int* items;
>
> };
>
> I want to write a unit test program to test foo::addItem(), to do that
> the test program needs to know the contents of foo::items.
I agree with James Kanze on this. As the class above sits, there is no
reason to test addItem because it need not do anything at all.
Let's try a more realistic example:
class Bar {
public:
virtual void update() = 0;
};
class foo {
// implementation is irrelevant.
public:
void attach(Bar* b);
void detach(Bar* b);
void notify();
};
When Foo::notify() is called, all Bars who have been attached to that
foo should have their update() called, while bars that were attached but
then detached should not have their update() called.
The above, of course, is very testable, despite the fact that Foo's
internals are private.
> So I can add one more public function to class foo:
> int* getItems();
>
> But suppose in my case, the client code of class foo does not need
> getItems() at all, this function serves only for test in this case.
What external state changes when you add an item to a foo? Something has
to change or the function has no purpose.
Thanks for the replies most of which do clarify some good points about
what is and how to do unit test.
But I think there is a subtle difference to define "unit". I can not
agree with James Kanze more on unit test *when* the unit is a class,
but how about the unit is a function? A class' public function?
I am adapting Test Driven Development, TDD, into my daily programming.
Please bear with me, I am doing-it-before-learning-it. I designed my
class interface, without implementing the API functions, I started
designing my test class to test each API function. It is at this point
my question coming up.
I learned 2 practical ways in this discussion thread, one is to
"#define private public" and the other is as Philp said, it is
perfectly OK in TDD sense to define a slightly bloated API list.
I posted my question on 2 groups, C++ and Object, interestingly
enough, I see folks in C++ group unanimously think "unit" is class
while Object folks provide me more diverse viewpoints.
Thanks a lot.
> But I think there is a subtle difference to define "unit". I can not
> agree with James Kanze more on unit test *when* the unit is a class,
> but how about the unit is a function? A class' public function?
>
> I am adapting Test Driven Development, TDD, into my daily programming.
Kanze is a classically-trained "unit tester". In some circles "unit" is a QA
concept - specifically, if a test fails, you only need to inspect one unit.
So "units" are "things which are clearly delimited and accessible to
inspection". That should map onto C++ classes - specifically due to
overlapping requirements. C++ classes _should_ be "things which are clearly
delimited and accessible to inspection". Yet sometimes, by necessity, the
"unit" is a translation unit, or a header, or a peculiar include file, or a
global constant.
Under TDD, if a test fails during development, you only need to inspect (or
revert) the most recent edit. So Developer Tests and Unit Tests have
overlapping abilities and motivations. Many TDD tests will also allow you to
isolate faults to a small unit.
> Please bear with me, I am doing-it-before-learning-it. I designed my
> class interface, without implementing the API functions, I started
> designing my test class to test each API function. It is at this point
> my question coming up.
That's not really TDD. You start at the test, and write each test case to
illustrate one aspect of your target class. Only after you get the test to
tell you what to add to the class, next, do you add it. So imagine if your
method .activate() did not exist yet:
test_case
Foo aFoo
result = aFoo.activate
assert result == 42
The first time you run that, if activate does not exist yet, you add it.
Then you run it again, and "discover" that activate has no return value. The
third time, you run it and discover the return value is wrong. Only after
this rigorous review of the circumstances - to determine the test is failing
for the correct reason - do you put the actual logic inside the method.
You repeat this aggressive testing, in small cycles (and integrating between
each tiny twitch) to grow an interface.
> I posted my question on 2 groups, C++ and Object, interestingly
> enough, I see folks in C++ group unanimously think "unit" is class
> while Object folks provide me more diverse viewpoints.
"Class" is good for "Unit". But sometimes the Unit is one isolated group of
switches, between microscopic test pads, deep inside a big integrated
circuit.
--
Phlip
http://assert2.rubyforge.org/
> > I am adapting Test Driven Development, TDD, into my daily
> > programming.
> Kanze is a classically-trained "unit tester". In some circles
> "unit" is a QA concept - specifically, if a test fails, you
> only need to inspect one unit.
You mean I'm using a word in its standardly accepted meaning.
(Unit tests have been a required part of development for many,
many years now.)
> So "units" are "things which are clearly delimited and
> accessible to inspection".
That's more or less a definition of "unit", yes. In practice,
units are units---they're more or less the lowest level in a
hierarchial development.
> That should map onto C++ classes -
Why? That's the first time I've heard that. (There are a lot
of cases where they do map onto C++ classes.)
> specifically due to overlapping requirements. C++ classes
> _should_ be "things which are clearly delimited and accessible
> to inspection". Yet sometimes, by necessity, the "unit" is a
> translation unit, or a header, or a peculiar include file, or
> a global constant.
As a minimum, a "unit" is never less than a translation unit,
since current technology doesn't allow you to break things down
any finer. (Of course, a translation unit is often less than a
complete class.)
> Under TDD, if a test fails during development, you only need
> to inspect (or revert) the most recent edit.
I'm sorry, but that's bullshit. Regardless of the design
philosophy, if you have halfway decent unit tests, there is a
high probability that the error is somehow due to the most
recent edit. And regardless of the design philosophy, there's
always a small chance that something in the recent change has
triggered an error which was already there before. (That's one
of the meanings of undefined behavior---and TDD doesn't remove
undefined behavior from the language.)
> So Developer Tests and Unit Tests have overlapping abilities
> and motivations. Many TDD tests will also allow you to isolate
> faults to a small unit.
All unit tests allow you to more or less isolate faults to a
small unit. None are perfect, however.
> > Please bear with me, I am doing-it-before-learning-it. I
> > designed my class interface, without implementing the API
> > functions, I started designing my test class to test each
> > API function. It is at this point my question coming up.
> That's not really TDD. You start at the test, and write each
> test case to illustrate one aspect of your target class.
Which, of course, isn't true, because until you have at least
some idea as to what the class is to do, you can't write the
tests. You start by determining what the class is to do (in
most cases, that means some high level design). You don't start
by just typing in code, whether it is a test or anything else.
(I find it very hard to conceive that in this day and age,
people are still suggesting that we code before we think. And
proposing it as a silver bullet, no less.)
Some people do, actually. :-)
However it depends on how religious you are, and how strictly you want
to follow the dogmas.
If you just want to be able to say that you do TDD, you can start out
with the single test case
assert(false);
This will surely fail, and you are then free to start coding your
design. Just remember to compiler often, and make sure that the test
still fails!
Eventually, you will "discover" that the fault is not in your code,
but in the test case. Then it is time to "refine" the tests. If you
just don't call them unit tests, but use cases, you're done.
Instant TDD(tm).
Bo Persson
> > > So I can add one more public function to class foo:
> > > int* getItems();
> >
> > > But suppose in my case, the client code of class foo does not need
> > > getItems() at all, this function serves only for test in this case.
> >
> > What external state changes when you add an item to a foo? Something has
> > to change or the function has no purpose.
>
> Thanks for the replies most of which do clarify some good points about
> what is and how to do unit test.
>
> But I think there is a subtle difference to define "unit". I can not
> agree with James Kanze more on unit test *when* the unit is a class,
> but how about the unit is a function? A class' public function?
Even then. A function is called because it either (a) returns useful
data or (b) causes a useful side effect. In either case, one can test if
a well written function (member function or free) does what it is
supposed to do.
> I am adapting Test Driven Development, TDD, into my daily programming.
> Please bear with me, I am doing-it-before-learning-it. I designed my
> class interface, without implementing the API functions, I started
> designing my test class to test each API function. It is at this point
> my question coming up.
Your question should never come up in the above case. If you have done
the above, then your 'addItem' function has a defined effect. That
effect can be tested for.
> James Kanze wrote:
>> Which, of course, isn't true, because until you have at least
>> some idea as to what the class is to do, you can't write the
>> tests.
> Some people do, actually. :-)
>
> However it depends on how religious you are, and how strictly you want
> to follow the dogmas.
And how much benefit you'd like to get from forcing the implementation design to
emerge. Naturally, it might follow your preliminary sketches. But it might not.
Some people are not rigorous enough to design under such tight constraints...
--
Phlip
>
>> That's not really TDD. You start at the test, and write each
>> test case to illustrate one aspect of your target class.
>
> Which, of course, isn't true, because until you have at least
> some idea as to what the class is to do, you can't write the
> tests. You start by determining what the class is to do (in
> most cases, that means some high level design). You don't start
> by just typing in code, whether it is a test or anything else.
>
Here's where we differ. The above assumes you have a design which
defines your classes.
Often with TDD, you test and to code to a more abstract requirement and
the design (classes) follow the tests. Sometimes there's an agreed
interface, or a base class that is being extended, but often the tests
are testing an action for a reaction.
I've just been looking back through some of my tests and just about all
of my JavaScript tests are testing reaction to events and in one large
C++ project most of the tests test systems states. Set a threshold,
change something, look for the reaction.
Coupling tests too closely to classes makes refactoring much harder.
> (I find it very hard to conceive that in this day and age,
> people are still suggesting that we code before we think. And
> proposing it as a silver bullet, no less.)
>
I don't think anyone is suggesting that. What is being suggested is a
different way of thinking.
--
Ian Collins.
> >> That should map onto C++ classes -
> > Why? That's the first time I've heard that. (There are a
> > lot of cases where they do map onto C++ classes.)
> Um, we agree again!
> >> That's not really TDD. You start at the test, and write
> >> each test case to illustrate one aspect of your target
> >> class.
> > Which, of course, isn't true, because until you have at
> > least some idea as to what the class is to do, you can't
> > write the tests. You start by determining what the class is
> > to do (in most cases, that means some high level design).
> > You don't start by just typing in code, whether it is a test
> > or anything else.
> Here's where we differ. The above assumes you have a design
> which defines your classes.
The above assumes that you have at least some idea as to what
the class (or any other bit of code) will do before you start to
write it. I think we both also more or less agree that unless
it is written down, you don't really have any idea. Where we
disagree is that you seem to consider the unit tests a form of
being "written down", whereas I consider them code, just like
the rest---I don't know how to write a unit test until I have
some idea what is to be tested, i.e. what the unit shoud do.
And IMHO, I don't know that until it is written down.
For small applications, it's not unusual that the "written down"
part ends up as comments in the header (in Doxygen format, for
example). For larger applications, there'll almost always be
some sort of high level functional decomposition before I can
even think about "units", and that has to be written down.
> Often with TDD, you test and to code to a more abstract
> requirement and the design (classes) follow the tests.
Traditionally, that has been called prototyping, not testing:-).
It's almost essential for anything which interacts with a human.
It's of almost no use if you're implementing a protocol defined
by a standard.
Traditionally, you're supposed to throw the prototype out, once
you've learned from it. A rule that is often ignored (which may
account for the poor quality of some of the software out there).
But I suppose that you could call throwing it out simply an
intensive refactorizing, and the prototyping "testing".
Especially since the "throwing out" usually doesn't consist of
actually deleting the source code from the disk, and that the
rewrite often involves some copy/pasting:-).
> Sometimes there's an agreed interface, or a base class that is
> being extended, but often the tests are testing an action for
> a reaction.
In which case, you probably have some idea as to what the action
or reaction should be. And perhaps even some constraints on it.
I'd write those out, in plain French (or whatever language I
happen to be using on the project). Maybe as comments in the
code; maybe even as comments in the unit tests. But in a human
language, at a higher level of abstraction than C++.
At a low level, I tend to work as if I were doing literate
programming, even when I'm not using literate programming tools.
The C++ code is an end product, not the means. And it's not the
only end product, since readability (and not just correct
implementation) is an important issue.
[...]
> > (I find it very hard to conceive that in this day and age,
> > people are still suggesting that we code before we think.
> > And proposing it as a silver bullet, no less.)
> I don't think anyone is suggesting that. What is being
> suggested is a different way of thinking.
Well, I've said from the start that you can't write any code
without first thinking. Including a unit test. But I'd like to
insist on the fact that if you haven't written it out in your
native language, you haven't really thought it out.
> I've just been looking back through some of my tests and just about all
> of my JavaScript tests are testing reaction to events and in one large
> C++ project most of the tests test systems states. Set a threshold,
> change something, look for the reaction.
The above is something the OP should take note. "Look for the reaction"
implies that there is a defined reaction to look for. His original
example had no defined reaction, nothing to look for, therefore nothing
to test.
True.
> Where we
> disagree is that you seem to consider the unit tests a form of
> being "written down", whereas I consider them code, just like
> the rest---I don't know how to write a unit test until I have
> some idea what is to be tested, i.e. what the unit shoud do.
> And IMHO, I don't know that until it is written down.
>
Not really, the written down will be some form of requirement, be that a
clause in a traditional requirements specification, or an XP style user
story. Given a requirement, my view of TDD is that it's another form of
functional decomposition. You know what your end gaol is, you know the
steps to take you there and you follow them. The smaller those steps,
the better.
> For small applications, it's not unusual that the "written down"
> part ends up as comments in the header (in Doxygen format, for
> example). For larger applications, there'll almost always be
> some sort of high level functional decomposition before I can
> even think about "units", and that has to be written down.
>
With TDD, the names of the tests replace the comments. The tests are
the detailed design and the examples of how to use the code. The
acceptance tests are the higher level requirements. If these are
written correctly, either by the customer or in a form they can
understand, the paper requirements can be discarded. I have only had
one client bold enough to do this!
>> Often with TDD, you test and to code to a more abstract
>> requirement and the design (classes) follow the tests.
>
> Traditionally, that has been called prototyping, not testing:-).
> It's almost essential for anything which interacts with a human.
> It's of almost no use if you're implementing a protocol defined
> by a standard.
>
> Traditionally, you're supposed to throw the prototype out, once
> you've learned from it. A rule that is often ignored (which may
> account for the poor quality of some of the software out there).
> But I suppose that you could call throwing it out simply an
> intensive refactorizing, and the prototyping "testing".
> Especially since the "throwing out" usually doesn't consist of
> actually deleting the source code from the disk, and that the
> rewrite often involves some copy/pasting:-).
>
Refactoring is part of the process of improving the design. I think you
would enjoy "Refactoring to Patterns" by Joshua Kerievsky.
>> Sometimes there's an agreed interface, or a base class that is
>> being extended, but often the tests are testing an action for
>> a reaction.
>
> In which case, you probably have some idea as to what the action
> or reaction should be. And perhaps even some constraints on it.
> I'd write those out, in plain French (or whatever language I
> happen to be using on the project). Maybe as comments in the
> code; maybe even as comments in the unit tests. But in a human
> language, at a higher level of abstraction than C++.
>
While I'd write them out as plain C++ or what ever language I happen to
be using on the project! In a way, they are in plain English, so long
as the tests are short and have meaningful names. That's why I always
forward declare the tests at the top of a file, even if the language
(such as PHP) does not require this. If the test's name can't express
its intent, the scope of the test is too broad.
>
>> I don't think anyone is suggesting that. What is being
>> suggested is a different way of thinking.
>
> Well, I've said from the start that you can't write any code
> without first thinking. Including a unit test. But I'd like to
> insist on the fact that if you haven't written it out in your
> native language, you haven't really thought it out.
>
To varying degrees of 'it'!
I like to class the design and naming of the tests as an important part
of this thinking process. The name (meaningful) and size (small) of the
tests is extremely important. All to often I see novices write a
monolithic test function with scores of asserts which tell the reader
very little. Break that up into a sequence of well named single
condition tests and the reader can see exactly what the code is supposed
to do. Many small, well named tests is a clear indicator that some who
claims to be doing TDD is. He or she can then tell what they have
broken when they make a change without having to step through the test.
--
Ian Collins.
[...]
> > Where we
> > disagree is that you seem to consider the unit tests a form of
> > being "written down", whereas I consider them code, just like
> > the rest---I don't know how to write a unit test until I have
> > some idea what is to be tested, i.e. what the unit shoud do.
> > And IMHO, I don't know that until it is written down.
> Not really, the written down will be some form of requirement, be that a
> clause in a traditional requirements specification, or an XP style user
> story. Given a requirement, my view of TDD is that it's another form of
> functional decomposition. You know what your end gaol is, you know the
> steps to take you there and you follow them. The smaller those steps,
> the better.
(I presume you mean "your end goal", but it's an interesting
Freudian slip:-). Except that you're probably American, and
would have written jail, and not gaol.)
The smaller the steps, the better, but to get the small steps,
you have to know the big ones. In a small application, you can
possibly go directly from user requirements to a detailed
specification of each unit, but as soon as the application takes
on a certain size, you're going to end up "designing" a number
of intermediate levels. (In many large applications, the first
couple of levels of functional decomposition give processes, not
what you'd normally consider a target for a unit test.)
> > For small applications, it's not unusual that the "written down"
> > part ends up as comments in the header (in Doxygen format, for
> > example). For larger applications, there'll almost always be
> > some sort of high level functional decomposition before I can
> > even think about "units", and that has to be written down.
> With TDD, the names of the tests replace the comments.
I'd be interesting in seeing that. For example, in a class that
I'm using right now, certain functions are documented with
'precondition: itemname != NULL". For a user, that's a very
important precondition. How do you specify that in a test, and
make it readable? How do you organize things so that I can
easily find the functions which interest me, and then see the
documentation which concerns them?
Everything I've ever seen and done suggests that you really need
separate detailed documentation, and that it is best done before
writing a single line of code, test or implementation. Literate
programming, in sum. (In the best run projects I've been on,
the header files were actually generated automatically from the
class documentation, done in Rational Rose.)
> The tests are the detailed design and the examples of how to
> use the code. The acceptance tests are the higher level
> requirements. If these are written correctly, either by the
> customer or in a form they can understand, the paper
> requirements can be discarded. I have only had one client
> bold enough to do this!
I'm very sceptical. I don't want to have to read C++ when I
need more general information, like the pre-conditions. Even
supposing that there are tests that reveal them, how do you
avoid the information getting lost in all of the other detail.
> >> Often with TDD, you test and to code to a more abstract
> >> requirement and the design (classes) follow the tests.
> > Traditionally, that has been called prototyping, not
> > testing:-). It's almost essential for anything which
> > interacts with a human. It's of almost no use if you're
> > implementing a protocol defined by a standard.
> > Traditionally, you're supposed to throw the prototype out,
> > once you've learned from it. A rule that is often ignored
> > (which may account for the poor quality of some of the
> > software out there). But I suppose that you could call
> > throwing it out simply an intensive refactorizing, and the
> > prototyping "testing". Especially since the "throwing out"
> > usually doesn't consist of actually deleting the source code
> > from the disk, and that the rewrite often involves some
> > copy/pasting:-).
> Refactoring is part of the process of improving the design. I
> think you would enjoy "Refactoring to Patterns" by Joshua
> Kerievsky.
The problem is perhaps more psychological. If someone is told
that they are to refactor some code, they will generally try to
use the original code, even (perhaps) to the point of "forcing"
the new design in order to do so. I know that many recent
authors about refactoring insist on not being afraid to rewrite.
But the name itself suggests that you're doing something to the
old code (other than just throwing it out). Where as I prefer
to take the approach that you're starting from scratch, top
down; if some of the existing code does turn out to fit into the
new design (and it often does), so much the better, but this
consideration isn't taken into account until after you've done
the new design.
> >> Sometimes there's an agreed interface, or a base class that
> >> is being extended, but often the tests are testing an
> >> action for a reaction.
> > In which case, you probably have some idea as to what the
> > action or reaction should be. And perhaps even some
> > constraints on it. I'd write those out, in plain French (or
> > whatever language I happen to be using on the project).
> > Maybe as comments in the code; maybe even as comments in the
> > unit tests. But in a human language, at a higher level of
> > abstraction than C++.
> While I'd write them out as plain C++ or what ever language I
> happen to be using on the project! In a way, they are in
> plain English, so long as the tests are short and have
> meaningful names. That's why I always forward declare the
> tests at the top of a file, even if the language (such as PHP)
> does not require this. If the test's name can't express its
> intent, the scope of the test is too broad.
I'm still quite sceptical: I suppose that you also break the
tests into sections, perhaps with different namespaces, in order
to specify exactly what functions (or functionalities) are
concerned? And what about "external" references---often, an
idea can be made much clearer by refering to some external
concepts. (The documentation of my FFmt class: "An ostream
manipulator which defines a Fortran format F. Thie manipulator
is basically the equivalent to the "%n.mF" speicification in
printf, or Fn.m in Fortran." How could you possibly express
that in the name of a single test function? Of course, it's not
complete; the documentation does go on to express in detail what
is going on---with references to a pattern described in another
class---but for many programmers, just that one sentence is all
that is needed.) And how do you possibly describe the
constraints on a policy class, used to instantiate a template?
And that's just the low level stuff. The higher up you go, the
less appropriate C++ becomes as the description language.
> >> I don't think anyone is suggesting that. What is being
> >> suggested is a different way of thinking.
> > Well, I've said from the start that you can't write any code
> > without first thinking. Including a unit test. But I'd
> > like to insist on the fact that if you haven't written it
> > out in your native language, you haven't really thought it
> > out.
> To varying degrees of 'it'!
> I like to class the design and naming of the tests as an
> important part of this thinking process. The name
> (meaningful) and size (small) of the tests is extremely
> important.
Certainly. At the lowest level, I can imagine your solution
working for some types of things. I don't see too well how it
could apply at higher levels, however, and I don't see how it
could be used for other types of low level things. How would
you document that the instantiation class of std::vector must be
CopyConstructable and Assignable, for example? How would you
document the requirements for the Allocator? For that matter,
do you really want to document them for std::vector, given that
they're the same for all of the containers; isn't the solution
adopted by the standard a lot better: give the concepts a name,
and document what that name means elsewhere (which, when it
comes right down to it, is what I did with FFmt---except that I
suppose the name, Fn.m in Fortran, to be an already known
concept).
> All to often I see novices write a monolithic test
> function with scores of asserts which tell the reader very
> little. Break that up into a sequence of well named single
> condition tests and the reader can see exactly what the code
> is supposed to do. Many small, well named tests is a clear
> indicator that some who claims to be doing TDD is. He or she
> can then tell what they have broken when they make a change
> without having to step through the test.
Guilty as charged. My current test framework certainly doesn't
lend itself to this sort of stuff. But then, I've never been
motivated to modify it so that it would, since I do work in the
opposite direction: from specification and documentation to
code. Still, I'd be interested in seeing what you use as a test
framework---I'm currently rewriting parts of mine to accept test
specifications in XML, so it's a good occasion to integrate new
ideas.
FWIW: you can see a bit of my work at my site
(kanze.james.neuf.fr). It doesn't explain how I got to that
state, but for most of the stuff: I wrote the documentation in
the header file first, then the function signatures. The
implementation of the functions and the tests were generaly done
in parallel, and in the more complicated cases, I'd start with
just a few of the function signatures, and expand once they
worked. There are more tests than I've seen in a lot of
publicly available software, but it could still be better.
Here is more realistic capture of my problem, the original post is
over-simplified, but I do learn a lot from your guys' discussion,
class repo {
public:
repo();
/**
* Add one repo search path, if the path satisfies all the
requirements, this path will be stored internally.
*
* @returns 0 if succeeds
*/
int addSearchPath(string path);
/**
* Retrieve all the item from all the search paths
*/
std::vector<item> getAllItems();
private:
vector<string> pathList;
};
Given the above class, my unit test is to cover addSearchPath(), so
I can do either of the followings:
1. Just use the 2 public functions since they are the real API that
customer code will use.
2. Unit test code accesses the private data directly to verify
addSearchPath().
I guess James Kanze would suggest #1, but for my case I lean to #2.
The reason is unit test using #1 requires quite a bit setup for class
item while this unit test just want to test addSearchPath() does cover
all the requirements for a valid search path, so #1 seems to me too
much academic.
#2 serves my purpose very well and I do not want to add more API to
return the internal private data, I will use #define private public
trick.
Please throw your bricks.
>> Where we
>> disagree is that you seem to consider the unit tests a form of
>> being "written down", whereas I consider them code, just like
>> the rest---I don't know how to write a unit test until I have
>> some idea what is to be tested, i.e. what the unit shoud do.
>> And IMHO, I don't know that until it is written down.
>>
> Not really, the written down will be some form of requirement, be that a
> clause in a traditional requirements specification, or an XP style user
> story. Given a requirement, my view of TDD is that it's another form of
> functional decomposition. You know what your end gaol is, you know the
> steps to take you there and you follow them. The smaller those steps,
> the better.
You American you!! You are just not smart enough to think of all your class
details outside of code, where they are safe from the icky details of
implementation, best left to servants!
You just want to leap into coding, without being rigorous enough to prove you
can code it all in your head first, like me!
--
Phlip
I would typedef every template instantiation, partly because it's
self-documenting, and because declaring the instantiation point carefully can
avoid obscure bugs in template expansion.
> Given the above class, my unit test is to cover addSearchPath()
What is the effect the added search path will have on other, external objects?
Recall this is not "unit" testing - you are allowed to use more than one object
at a time!
, so
> I can do either of the followings:
> 1. Just use the 2 public functions since they are the real API that
> customer code will use.
> 2. Unit test code accesses the private data directly to verify
> addSearchPath().
3 - detect the effect the added search path will have on behavior.
> I guess James Kanze would suggest #1, but for my case I lean to #2.
He is discussing unit testing, not TDD...
It was wasn't it :)
> Except that you're probably American, and
> would have written jail, and not gaol.)
>
Hey, no need for insults! I'd have thought my spelling and timezone
would be enough of a hint.
I'll address the rest of the post later today when I've dug up some
unencumbered examples.
--
Ian Collins.
Two insults in one day, what am I doing wrong?
--
Ian Collins.
I didn't mean it as an insult; I'm American myself (originally,
at any rate). Living where I do, however, I see enough of both
spellings that I don't actually notice which is being used (and
a lot of British programmers write "program", rather than
"programme" for a computer program). The above comment was
meant more as a hint, since I'm not sure how many Americans
would recognize gaol otherwise.
> I'll address the rest of the post later today when I've dug up
> some unencumbered examples.
I know the problem. You write code to get the job done, not to
bring evidence for a certain point. Which means that most of
the real examples are buried in a lot of stuff that has nothing
to do with the immediate point.
I find it just as difficult to present simple examples which
show my own style.
> class repo {
> public:
> repo();
> private:
> vector<string> pathList;
> };
Or 3: both. There are many different levels of testing, and it
may be useful for development purposes to "see" the internals.
(Why not specify some logging output? That way, the added code
might be useful in the final application as well.)
> I guess James Kanze would suggest #1,
At some point or another, you need #1. You can't release the
code without it.
> but for my case I lean to #2.
> The reason is unit test using #1 requires quite a bit setup
> for class item while this unit test just want to test
> addSearchPath() does cover all the requirements for a valid
> search path, so #1 seems to me too much academic.
#2 doesn't really cover all of the requirements, if the
requirements include actually using the added value in some way,
so that it affects the return value of getAllItems(). And if
it's that much work to set it up, then you need to get a better
test harness.
> > private:
> > vector<string> pathList;
> I would typedef every template instantiation, partly because
> it's self-documenting, and because declaring the instantiation
> point carefully can avoid obscure bugs in template expansion.
For a simple case like this, I don't know, but in general, yes.
> > Given the above class, my unit test is to cover addSearchPath()
> What is the effect the added search path will have on other,
> external objects?
> Recall this is not "unit" testing - you are allowed to use
> more than one object at a time!
The original question was about unit testing, so it is unit
testing. Not that that prevents him from using other objects.
> , so
> > I can do either of the followings:
> > 1. Just use the 2 public functions since they are the real API that
> > customer code will use.
> > 2. Unit test code accesses the private data directly to verify
> > addSearchPath().
> 3 - detect the effect the added search path will have on behavior.
> > I guess James Kanze would suggest #1, but for my case I lean to #2.
> He is discussing unit testing, not TDD...
Obviously, since the original poster apparently already has a
design, and knows what the class is supposed to do. Regardless
of how you arrive at the design, you need unit tests. (It was
my impression that TDD was supposed to give them to you as a
result of the design.)
No offence taken! That was a too early in the morning joke...
> Living where I do, however, I see enough of both
> spellings that I don't actually notice which is being used (and
> a lot of British programmers write "program", rather than
> "programme" for a computer program). The above comment was
> meant more as a hint, since I'm not sure how many Americans
> would recognize gaol otherwise.
>
Ah, the joys of a common language. All the more reason to express
intent in something unambiguous like C++, or possibly French. Joking
asside, how often do you see N programmers interpret a written
requirement in N different ways?
> > I'll address the rest of the post later today when I've dug up
> > some unencumbered examples.
>
> I know the problem. You write code to get the job done, not to
> bring evidence for a certain point. Which means that most of
> the real examples are buried in a lot of stuff that has nothing
> to do with the immediate point.
>
> I find it just as difficult to present simple examples which
> show my own style.
>
Life would be so much eaier if we didn't have to work for others.
Ian.
I have a strong feeling that this seemingly simple class is trying to do
way too much. I have this feeling because apparently, the obvious and
correct solution requires "quite a bit of setup". What kind of setup are
you talking about? Isn't the Item class already implemented (with all
the attendant tests?)
"path satisfies all the requirements" sounds like a function to me, one
that can and should be implemented independently of "addSearchPath".
> #2 serves my purpose very well and I do not want to add more API to
> return the internal private data, I will use #define private public
> trick.
Number 2 may not serve your purpose at all. It may be that the best
implementation is to get all the items out of a path when addSearchPath
is called and store a vector of *them* instead of storing a vector of
paths... or maybe some of the work should be done in addSearchPath,
while the rest is done in getAllItems. In other words, by testing the
implementation directly as you are proposing, you are also locking in
one particular implementation out of many. You are blowing encapsulation
out of the water.
> James Kanze wrote:
>> Phlip wrote:
>>> That should map onto C++ classes -
>> Why? That's the first time I've heard that. (There are a lot
>> of cases where they do map onto C++ classes.)
> Um, we agree again!
Unit tests (and many TDD tests) should target "units", which are code elements
that are clearly delimited and accessible to inspection. Failure of a true Unit
Test must implicate nothing outside its target unit.
Classes should also be clearly delimited and accessible to inspection.
That does not mean units _must_ be classes. For example, if I code-reviewed your
unit test and said, "This is a bad test because the unit it addresses is not one
class," I have brought nothing to the code review.
Most unit tests do indeed address classes, as a happy coincidence. A pattern of
_all_ the tests not focusing on classes should raise a warning...
> Here's where we differ. The above assumes you have a design which
> defines your classes.
I am so smart that I can heroically define all my classes in my head before
coding them. Etc...
BTW here's a little story about my worksite. Long before I got there, someone
wrote a script, without tests, with about 2 000 lines of >cough< Ruby. (The
equivalent of like 6 000 lines of C++.) It since ballooned up to like 3 000.
Several engineer-weeks of labor in total.
Last year, I strapped a GUI onto it, and wrote some really ugly tests that
called the whole thing. The script calls a huge batch that runs in a background
process, and the tests simply set up the complete input, run the same batch as
the process would run, then checks all the results in a long list of assertions.
The tests are just aggressive enough to make the script slightly harder to add
bugs too, and slightly less difficult to add features to. The tests are
painfully slow, and we only run them on integration server. We add 5 000 lines
of crappy (yet stable) tests. (Not one of them focused on a "unit"!;)
Recently our product manager asked for just one more feature. I got permission
for a rewrite. I commented every line of all that cruft out, and we started again.
Today is day 2. By day 3 (via 8-hour days), I know that we 6 coders will be
finished with the rewrite. We are using pure TDD, and promiscuous pairing. That
means (even if we are a hothead who _knows_ what the architecture of some module
is going to be) every 2 hours we swap pairs, going to the module in the
application that we are /least/ familiar with. That means we leave whatever
awesome architecture we were about to finish in the hands of someone least
familiar with it. Including two guys who started last week with no Ruby coding
experience.
By tomorrow afternoon, when we are done, any of the six guys could lead a new
pair, if necessary, to add any new feature, anywhere in the application. And
after pure TDD, merciless refactoring, and continuous integration, we will have
like 600 lines of Ruby in total. The new GUI will not create a thread to run the
script, and the script will be completely cancel-able and restartable. Oh, and
we will have 2 000 lines of super-fast tests, too. We know the code will have
zero bugs, and will exceed the old feature list. Our operators will be able to
start using it around Wednesday.
(And rest assured that if our servers crash, we will rapidly lose oodles of
money, too!;)
Our new code will stay clean like that for as long as this project lasts, no
matter who works on it, or what features they add.
I am not open to any braggadocio concocted rationales why what we are doing is
somehow vaingloriously wrong, and that all 7 guys are somehow too stupid and
/fanfaron/ not to notice it.
--
Phlip
> Two insults in one day, what am I doing wrong?
Hey - /I'm/ one, so I am totally allowed!!
> But this concept really comes out of programming by contract,
> rather than test driven design (which can easily be used to
> avoid specifying the necessary contracts).
What an unsupportable, straw-person argument.
People doing TDD are forbidden to use any other techniques they have ever
learned, folks!
> Ah, the joys of a common language. All the more reason to
> express intent in something unambiguous like C++, or possibly
> French.
French has Québecois, just like English has American (although
obviously, the influence of Québecois in the international
community is somewhat less than that of American). In fact, you
can be as precise, or as imprecise, as you want in French, just
as you can in English (or any other language I know). As you
want, or as you can---you'd be surprised at the number of
engineers who don't really master their native language, despite
what Dijkstra said: "Besides a mathematical inclination, an
exceptionally good mastery of one's native tongue is the most
vital asset of a competent programmer."
(http://www.cs.utexas.edu/users/EWD/ewd04xx/EWD498.PDF)
I think his point is somewhat related to the one I'm trying to
make: you have to have a very clear idea as to what the code is
supposed to do before you can write anything (test,
implementation or documentation). And IMHO, having a clear idea
means being able to express it in your native tongue, preferably
in writing.
> Joking asside, how often do you see N programmers interpret a
> written requirement in N different ways?
And how many times to you see written requirements which can
easily be interpreted in N different ways?
The first step is always to get a written requirement that
cannot be interpreted in N different ways, and to ensure that
all of the people working on the project are interpreting it in
the same way. I believe that this is what you are trying to do
with your tests, but I just don't believe that it's possible.
The expressivity (and the precision, when one has "an
exceptionally good mastery of one's native tongue) are orders of
magnitude higher in a human language; after all, it's been
evolving for centuries to reach a stage of perfection that
allows expression of all possible ideas, with as much precision
as desired (or as much ambiguity, if that's what is desired).
The real key, of course, is the mastery of the human language
being used. But my experience more or less coincides with that
of Dijkstra: those people who can't express themselves clearly
in their native language make a mess of the C++ as well. (And
of course, depending on the project, you might not be using your
native language. And while generally, the better you master
your native language, the better you can learn to master a
foreign language, and most truly competent programmers have no
trouble mastering another language, there are exceptions---I
have met one or two truly competent programmers who were
hopeless in foreign languages, despite being able to express
themselves perfectly in their own language.)
> Unit tests (and many TDD tests) should target "units", which
> are code elements that are clearly delimited and accessible to
> inspection. Failure of a true Unit Test must implicate nothing
> outside its target unit.
In an ideal world. In practice, of course, it's impossible. A
unit test may fail because of an error in the code its testing,
but it may also fail because of an error in the test itself, in
the test framework, in the framework used by the code it's
testing, in the compiler, in the OS, in the machine hardware...
(Hopefully, most of the time, we can safely assume that the
error is either in the code being tested or the test. At least
until proven otherwise. Although when I first started using C++
professionally, over half the errors detected by my unit tests
were due to errors in the compiler.)
> Classes should also be clearly delimited and accessible to
> inspection.
You'll have to define your terms better. Classes should
definitely be clearly delimited, and have rigorously defined
interfaces and behavior. So should units which aren't classes.
But what do you mean by "accessible to inspection"? Code
review? ("Inspection" seems to be a human activity here;
although some forms of inspection can be mechanized, surely none
to a sufficient degree to ensure quality in themselves.)
> That does not mean units _must_ be classes. For example, if I
> code-reviewed your unit test and said, "This is a bad test
> because the unit it addresses is not one class," I have
> brought nothing to the code review.
> Most unit tests do indeed address classes, as a happy
> coincidence. A pattern of _all_ the tests not focusing on
> classes should raise a warning...
And now we're in agreement. Although I think it somewhat
depends: in a library of mathematical functions, there may not
be many classes, so tests will naturally not focus on classes.
But at least in the domains I'm active in, most "units"
correspond to a single class (and the second largest group,
albeit very much smaller, are units which consist of a very
small number of classes working very closely together).
> > Here's where we differ. The above assumes you have a design
> > which defines your classes.
> I am so smart that I can heroically define all my classes in
> my head before coding them. Etc...
And that I don't believe. I've never met anyone that brilliant.
[...]
> I am not open to any braggadocio concocted rationales why what
> we are doing is somehow vaingloriously wrong, and that all 7
> guys are somehow too stupid and /fanfaron/ not to notice it.
The braggadocio is in the part I clipped. That you're all so
brilliant that you can do all the design work in your head,
think of all the test cases in a few days, without any written
support, etc. (Of course, it's a pretty small project, from
what you describe. But even then.)
#3 add a getPaths op.
Then you can define a post-condition for the addSearchPath op.
Regards,
Steven Perryman
Steve, that was an incredibly naive answer. The post-condition to
addSearchPath is, and should be, the effect it has on getAllItems.
Adding a getPaths function, or as others have suggested, just making
pathList public to the testing harness, fails to make that post-
condition testable.
The tests the OP needs are something like:
repo r;
int result = r.addPath( "badpath" );
assert( result != 0 );
assert( r.getAllItems().size() == 0 );
---
repo r;
int result = r.addPath( "goodpath" );
assert( result == 0 );
assert( r.getAllItems().size() == expectedSize );
// examine the items in the container to make sure they are
// the expected ones.
---
etc...
The fact that he claims that such tests are difficult because it
"requires quite a bit of setup for class item" suggests to me that his
'item' abstraction is ill-defined, and or he needs another abstraction
"Path".
The above is just too funny to pass up. Hand that sentence to an
English professor some time. He/she will enjoy the laugh. (I always
find it funny when someone [including myself] talks about how
important some particular skill is, while plainly demonstrating that
he/she doesn't have it. :-)
>>#3 add a getPaths op.
>>Then you can define a post-condition for the addSearchPath op.
> Steve, that was an incredibly naive answer. The post-condition to
> addSearchPath is, and should be, the effect it has on getAllItems.
If such a relationship can be established.
Can it done ?? And should it be done ??
> Adding a getPaths function, or as others have suggested, just making
> pathList public to the testing harness, fails to make that post-
> condition testable.
FORALL np = SELF.getPaths() , op = OLD.getPaths() ,
d = difference(np,op) :
/* 1 */ d.size IN [0,1]
/* 2 */ (RESULT = 0) = ( (d = 1) AND d.contains(path) )
#1 states that either the set of paths changed or they did not.
#2 states (on the assumption that a duplicate path is considered an
error) that if the given path "satisfies all the requirements" , the
change to the paths set corresponds exactly to the given path.
What you failed to discern is that no obvious relationship appears to
exist between addSearchPath and getAllItems. Therefore a post-condition
using getAllItems cannot be defined.
OTOH there is a precise relationship between addSearchPath and the path
set. Therefore that is the better basis for a post-condition.
And if so inclined, a relationship between the path set and getAllItems
can probably be discerned (resulting in an invariant/post condition
thereof) .
> The fact that he claims that such tests are difficult because it
> "requires quite a bit of setup for class item" suggests to me that his
> 'item' abstraction is ill-defined, and or he needs another abstraction
> "Path".
What became immediately obvious is that paths are the core concept
in the repo type, not items.
Which meant your claim :
"The post-condition to addSearchPath is, and should be, the effect it
has on getAllItems"
is somewhat naive.
Regards,
Steven Perryman
The above quote isn't Dutch, is it? So what does it show about Dijkstra's
command of his native language?
Best
Kai-Uwe Bux
I'm afraid I don't understand. To begin with, it looks like
very good English to me, and I don't see why an English
professor would find anything to say about it. And of course,
Dijkstra talked about "one's native tongue" (Dutch, in his
case), not English. Dijkstra's English, at least in his early
works, was pretty bad; in his later works, one hardly realized
that it wasn't his native tongue. (Of course, his English, even
in his earliest works, was far better than my Dutch.)
AOL.
What's wrong with it?
Cheers,
- Alf (revelling in off-topicality)
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
The OP requires that the relationship exist, so it should be done. He
has also said that testing the relationship is "difficult" though not
impossible.
> OTOH there is a precise relationship between addSearchPath and the path
> set. Therefore that is the better basis for a post-condition.
Given the interface of the repo class, there is no reason to require
that the path set be stored in any case. What matters is if
getAllItems returns the correct value, the pathList need not even
exist for getAllItems to work correctly. Testing the pathList, tests
the wrong thing.
> > The fact that he claims that such tests are difficult because it
> > "requires quite a bit of setup for class item" suggests to me that his
> > 'item' abstraction is ill-defined, and or he needs another abstraction
> > "Path".
>
> What became immediately obvious is that paths are the core concept
> in the repo type, not items.
I agree that Path is a core concept that is being ignored by the OP.
Once we assume a Path type, the post-condition of addSeearchPath
becomes much easier to express:
addSearchPath(Path path);
post: getAllItems() includes old getAllItems() + path.getItems()
> Which meant your claim :
>
> "The post-condition to addSearchPath is, and should be, the effect it
> has on getAllItems"
>
> is somewhat naive.
No. The whole point of the addSearchPath method is to modify the
result returned by getAllItems, any post-condition or test that
doesn't express that is missing the point.
> What's wrong with it?
ones native tongue
'one' is used as a pronoun, hence its possessive needs no apostrophe
However, a quick visit to Wikipedia reveals:
"Edsger Wybe Dijkstra [ ... ] was a Dutch computer scientist."
It also lists:
Born May 11, 1930, Rotterdam, Netherlands
Died August 6, 2002 (aged 72), Nuenen, Netherlands
So, English was not in fact his native language. So there is ... less
humor and/or irony involved than you appear to think.
Best wishes,
// Christian Brunschen
>> ones native tongue
>> 'one' is used as a pronoun, hence its possessive needs no apostrophe
> "Edsger Wybe Dijkstra [ ... ] was a Dutch computer scientist."
> So, English was not in fact his native language. So there is ... less
> humor and/or irony involved than you appear to think.
Si! Major props to the D-man.
And, at work, we integrate so often, under the house-rule "always write a
distinct integration comment that you might need to read later" we have taken to
using slang, chat, LOLCAT, etc...
> On Jul 1, 7:53 am, S Perryman <q...@q.com> wrote:
DT> Steve, that was an incredibly naive answer. The post-condition to
DT> addSearchPath is, and should be, the effect it has on getAllItems.
>>If such a relationship can be established.
>>Can it done ?? And should it be done ??
> The OP requires that the relationship exist, so it should be done. He
> has also said that testing the relationship is "difficult" though not
> impossible.
The OP from the outset appears to have a mind-set issue of adding
additional functionality for auxiliary purposes (testing etc) .
While I fundamentally disagree with that viewpoint, I agree with it from
the design for testability (DFT) viewpoint. The problem for me actually
becomes :
1. What is the *minimum* functionality that I can add in order to achieve
maximum testability
2. What is the ROI for 1.
I will term 1/2 as MIN/ROI respectively.
>>OTOH there is a precise relationship between addSearchPath and the path
>>set. Therefore that is the better basis for a post-condition.
> Given the interface of the repo class, there is no reason to require
> that the path set be stored in any case. What matters is if
> getAllItems returns the correct value, the pathList need not even
> exist for getAllItems to work correctly. Testing the pathList, tests
> the wrong thing.
The current requirement for repo is to have an associated set of paths
which are used to generate the items. How that set of paths comes into
being etc is a moot point, but the set exists nevertheless.
>>What became immediately obvious is that paths are the core concept
>>in the repo type, not items.
> I agree that Path is a core concept that is being ignored by the OP.
> Once we assume a Path type, the post-condition of addSeearchPath
> becomes much easier to express:
> addSearchPath(Path path);
> post: getAllItems() includes old getAllItems() + path.getItems()
You are on the right track, but the coupling between the ops is poor.
Given that there is a relationship between repo and paths, and paths
generate items, the better way to define your types is :
type Path
{
coll<Item> getItems() ;
}
type repo
{
coll<Path> getPaths() ;
coll<Item> getAllItems() ;
invariant : getAllItems() = union(FORALL e IN getPaths: e.getItems() )
// post : the 'difference' post-condition expressed in terms of
// getPaths()
int addSearchPath(Path) ;
}
In summary :
1. Correctness is guaranteed for addSearchPath (the set of paths is not
damaged by the addition of the new path etc) .
2. Correctness is axiomatically constructed for getAllItems as an
invariant. Invariants are the strongest condition that a type can have.
3. The addSearch op is no longer coupled to getAllItems.
4. For the repo type, MIN is implementing getPaths, and the post/invariant
condition.
5. ROI is very high, as I get 1-3, and the means to show that addSearchPath
and getAllItems work in repo for any given paths.
>>Which meant your claim :
>>"The post-condition to addSearchPath is, and should be, the effect it
>>has on getAllItems"
>>is somewhat naive.
> No. The whole point of the addSearchPath method is to modify the
> result returned by getAllItems, any post-condition or test that
> doesn't express that is missing the point.
The point of addSearchPath is to add a search path to the set associated
with repo. The point of getAllItems is to use that set to generate an item
set. Given that a user can invoke addSearchPath ad-nauseum without ever
invoking getAllItems, there is no requirement to couple them together
(which is what your post-condition does) .
Regards,
Steven Perryman
>> What's wrong with it?
>
> ones native tongue
>
> 'one' is used as a pronoun, hence its possessive needs no apostrophe
English is not my mother tongue, which may explain that this rule is new
to me. I just wonder why Merriam-Websters then explains "mother tongue" as
one's native language
> On Jun 30, 1:21 pm, Ian Collins <ian-n...@hotmail.com> wrote:
>>With TDD, the names of the tests replace the comments.
> I'd be interesting in seeing that. For example, in a class that
> I'm using right now, certain functions are documented with
> 'precondition: itemname != NULL". For a user, that's a very
> important precondition. How do you specify that in a test, and
> make it readable? How do you organize things so that I can
> easily find the functions which interest me, and then see the
> documentation which concerns them?
A pre-condition is not a test artifact, because it shows a defect
in a component user, not the component IUT. That aside, you would
write the predicates in the same form you would for testing the
output of a service/function.
Regards,
Steven Perryman
> Christian Brunschen wrote:
>> "Edsger Wybe Dijkstra [ ... ] was a Dutch computer scientist."
>> So, English was not in fact his native language. So there is ... less
>> humor and/or irony involved than you appear to think.
> Si! Major props to the D-man.
> And, at work, we integrate so often, under the house-rule "always write
> a distinct integration comment that you might need to read later" we
> have taken to using slang, chat, LOLCAT, etc...
A bit of up-front domain analysis on Dijkstra would have saved you
the embarrassment of producing a defective comment ...
> A bit of up-front domain analysis on Dijkstra would have saved you
> the embarrassment of producing a defective comment ...
Please find the post where I said D's native language was English.
> ones native tongue
From the alt.usage.english FAQ: ``The ONLY personal possessive
pronoun with an apostrophe is "one's"''.
(http://alt-usage-english.org/excerpts/fxwheret.html.)
This is probably due to the fact that the personal pronouns
still have the case system (nominative, oblique and genitive,
e.g. I/me/ny, he/him/his), in which the possessive (genitive) is
just another alternative, and to the fact that using the
apostrophe would cause ambiguity ("its", possessive, "it's",
contraction of "it is") in some cases. Neither of these
considerations applies to "one".
Ayup:
http://www.bartleby.com/141/strunk.html#1
Congrats to Dijkstra's editor!
(Or is that The Editor of Dijkstra by now?)
elsethread:
> Please find the post where I said D's native language was English.
__ >crickets...<
> S Perryman wrote:
After a look, you did not (so apologies due) .
In fact, looking thru the thread, no one did.
Regards,
Steven Perryman
> elsethread:
>> Please find the post where I said D's native language was English.
Why have you posted something relating to a posting of mine, in a
posting to a different person ... ??
> __ >crickets...<
Meaningless to me.