Date: Mon, 7 Dec 2020 14:42:40 +0000
There's a pattern for this:
class myclass {
friend class testing_backdoor; // no need for this to exist anywhere,
and have a linter make sure non-test code doesn't have a definition
private:
int p;
};
then in your test:
struct testing_backdoor {
static int get_p(myclass const& x) { return x.p; }
};
Every test file only defines the backdoors it needs, so encapsulation
violations are defined at the top of the test file in this class, as well
as on every use - classes with static member functions, unlike namespaces,
require explicit qualification with testing_backdoor::.
Do name it exactly "testing_backdoor" - that's an important tell, it's
long, and obvious, and greppable.
Namespaces for this purpose are wrong, because "using namespace" exists.
On Sun, Dec 6, 2020 at 9:18 PM Henry Miller via Std-Proposals <
std-proposals_at_[hidden]> wrote:
> I find that where this is an an issue it is best solved by adding classes.
> You can make the implementation details a class (or even struct), and the
> public interface just calls the private classes. That is your public class
> has one thing in private, a pointer to the class with more information.
> See also the pimpl pattern, which is most for a different reason, but can
> achieve the ends you want.
>
> --
> Henry Miller
> hank_at_[hidden]
>
>
>
> On Sun, Dec 6, 2020, at 14:19, chibane nadir via Std-Proposals wrote:
>
>
> @Peter: usually it is true to avoid testing private members, but for the
> sake of preventing a subsequent refactor of public API from creating side
> effects on private members, we need to create test cases with the purpose
> of fixing invariant in our classes. Also if you look at it in different
> manner, private members are part of the logic of the classes, which means
> not testing them could create logic bugs (what i call smart bugs) and
> refactoring them into public member would expose a lot of the guts of the
> implementation.
>
> I used to test private members by checking their effects on public members
> (transitive side effects), but i run into a lot of cases where you cannot
> pin point the effect of a private member if the public member depends on
> many of them.
>
> @Arthur O'Dwyer : ' *Namespaces, unlike classes, are open.' *very true,
> it would be a great idea if a friended namespace will be like an anonymous
> namespace, i.e. static to the translation unit it was defined in. expl:
>
> *friend namespace XYZ {}; // the friend keyword changes this namespace
> into a "static" namespace if we can say that!*
> *class toBeTested*
> *{*
> * using namespace XYZ;*
> *}*
>
> *_at_Ville Voutilainen : *adding an #ifdef preprocessor condition, adds to
> the maintainability of the class, and convey the meaning that testabilty is
> optional tho test development is almost mandatory in software building.
> My motivation about this proposal is to:
> - unrestrict the way we test our classes,
> - keep implementation details hidden if they should be hidden,
> - avoid dogmas of "how to use" or "not to use".
> - unleash creativity (I'm pretty sure someone will find an interesting way
> to use this feature other than its intended use)
> - and for projects which didn't implement testing from the beginning, they
> just have to create a friend namespace with functions that shadows the
> class API, and test the members of that friend namespace, one API at a time.
>
> please advise.
>
> Nadir
> Le dimanche 6 décembre 2020 à 10:24:46 UTC+1, Peter C++ via Std-Proposals <
> std-proposals_at_[hidden]> a écrit :
>
>
> To start with, you should not test private stuff. It is private, so it
> might change. Binding tests to the private parts makes them harder to
> change, because of the tests, that should make software easier to refactor
> and change.
>
> Peter
> (Test infected since 1997)
>
> sent from a mobile device so please excuse strange words due to
> autocorrection.
> Peter Sommerlad
> peter.cpp_at_[hidden]
> +41-79-432 23 32
>
> On 6 Dec 2020, at 02:57, chibane nadir via Std-Proposals <
> std-proposals_at_[hidden]> wrote:
>
>
> Hello Team,
> for the purpose of TDD, there is a problem with testing private data
> members and member functions. some call it black box testing and others do
> the nasty "#define private public" just to shortcut the visibility of
> private and protected members to test the classes.
> I suggest to add the feature of "friend namespace" like the following:
>
> namespace XYZ
> {
> // define here your functions and classes
> void test_object_private_data_member_D(object* self,...);
> }
>
> class object
> {
> // private data members, and member functions
> 'sometype' D;
> // public data members, and member functions
>
> // for the purpose of testing this class let's include the members of
> namespace XYZ as friends so we can access private and protected
> // members of the current class
> private:
> using friend namespace XYZ; // <---- (A)
> };
>
> (A): at this point all the functions and classes defined in the namespace
> XYZ above will be inserted in the class "object" as friend functions and
> classes, likewise we will write test cases based on these friend functions
> and classes since they have access to all
> "object" class no matter what is their visibility (private, protected or
> public), and avoiding the need to use the nasty macro hack
> '#define private public'
>
> i can show a sample of how i use friend functions to create test cases,
> for interested people.
>
>
>
>
>
>
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
class myclass {
friend class testing_backdoor; // no need for this to exist anywhere,
and have a linter make sure non-test code doesn't have a definition
private:
int p;
};
then in your test:
struct testing_backdoor {
static int get_p(myclass const& x) { return x.p; }
};
Every test file only defines the backdoors it needs, so encapsulation
violations are defined at the top of the test file in this class, as well
as on every use - classes with static member functions, unlike namespaces,
require explicit qualification with testing_backdoor::.
Do name it exactly "testing_backdoor" - that's an important tell, it's
long, and obvious, and greppable.
Namespaces for this purpose are wrong, because "using namespace" exists.
On Sun, Dec 6, 2020 at 9:18 PM Henry Miller via Std-Proposals <
std-proposals_at_[hidden]> wrote:
> I find that where this is an an issue it is best solved by adding classes.
> You can make the implementation details a class (or even struct), and the
> public interface just calls the private classes. That is your public class
> has one thing in private, a pointer to the class with more information.
> See also the pimpl pattern, which is most for a different reason, but can
> achieve the ends you want.
>
> --
> Henry Miller
> hank_at_[hidden]
>
>
>
> On Sun, Dec 6, 2020, at 14:19, chibane nadir via Std-Proposals wrote:
>
>
> @Peter: usually it is true to avoid testing private members, but for the
> sake of preventing a subsequent refactor of public API from creating side
> effects on private members, we need to create test cases with the purpose
> of fixing invariant in our classes. Also if you look at it in different
> manner, private members are part of the logic of the classes, which means
> not testing them could create logic bugs (what i call smart bugs) and
> refactoring them into public member would expose a lot of the guts of the
> implementation.
>
> I used to test private members by checking their effects on public members
> (transitive side effects), but i run into a lot of cases where you cannot
> pin point the effect of a private member if the public member depends on
> many of them.
>
> @Arthur O'Dwyer : ' *Namespaces, unlike classes, are open.' *very true,
> it would be a great idea if a friended namespace will be like an anonymous
> namespace, i.e. static to the translation unit it was defined in. expl:
>
> *friend namespace XYZ {}; // the friend keyword changes this namespace
> into a "static" namespace if we can say that!*
> *class toBeTested*
> *{*
> * using namespace XYZ;*
> *}*
>
> *_at_Ville Voutilainen : *adding an #ifdef preprocessor condition, adds to
> the maintainability of the class, and convey the meaning that testabilty is
> optional tho test development is almost mandatory in software building.
> My motivation about this proposal is to:
> - unrestrict the way we test our classes,
> - keep implementation details hidden if they should be hidden,
> - avoid dogmas of "how to use" or "not to use".
> - unleash creativity (I'm pretty sure someone will find an interesting way
> to use this feature other than its intended use)
> - and for projects which didn't implement testing from the beginning, they
> just have to create a friend namespace with functions that shadows the
> class API, and test the members of that friend namespace, one API at a time.
>
> please advise.
>
> Nadir
> Le dimanche 6 décembre 2020 à 10:24:46 UTC+1, Peter C++ via Std-Proposals <
> std-proposals_at_[hidden]> a écrit :
>
>
> To start with, you should not test private stuff. It is private, so it
> might change. Binding tests to the private parts makes them harder to
> change, because of the tests, that should make software easier to refactor
> and change.
>
> Peter
> (Test infected since 1997)
>
> sent from a mobile device so please excuse strange words due to
> autocorrection.
> Peter Sommerlad
> peter.cpp_at_[hidden]
> +41-79-432 23 32
>
> On 6 Dec 2020, at 02:57, chibane nadir via Std-Proposals <
> std-proposals_at_[hidden]> wrote:
>
>
> Hello Team,
> for the purpose of TDD, there is a problem with testing private data
> members and member functions. some call it black box testing and others do
> the nasty "#define private public" just to shortcut the visibility of
> private and protected members to test the classes.
> I suggest to add the feature of "friend namespace" like the following:
>
> namespace XYZ
> {
> // define here your functions and classes
> void test_object_private_data_member_D(object* self,...);
> }
>
> class object
> {
> // private data members, and member functions
> 'sometype' D;
> // public data members, and member functions
>
> // for the purpose of testing this class let's include the members of
> namespace XYZ as friends so we can access private and protected
> // members of the current class
> private:
> using friend namespace XYZ; // <---- (A)
> };
>
> (A): at this point all the functions and classes defined in the namespace
> XYZ above will be inserted in the class "object" as friend functions and
> classes, likewise we will write test cases based on these friend functions
> and classes since they have access to all
> "object" class no matter what is their visibility (private, protected or
> public), and avoiding the need to use the nasty macro hack
> '#define private public'
>
> i can show a sample of how i use friend functions to create test cases,
> for interested people.
>
>
>
>
>
>
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
Received on 2020-12-07 08:42:55