+ All Categories
Home > Documents > Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton,...

Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton,...

Date post: 26-Sep-2020
Category:
Upload: others
View: 0 times
Download: 0 times
Share this document with a friend
77
/ 47 Friendship in Service of Testing Gábor Márton, [email protected] Zoltán Porkoláb, [email protected] 1
Transcript
Page 1: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

Friendship in Service of Testing

Gábor Márton, [email protected]án Porkoláb, [email protected]

1

Page 2: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

Agenda

• Introduction, principals

• Case study

• Making the example better

• Vision

2

Page 3: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

Functional Programming

std::size_t fibonacci(std::size_t);ASSERT(fibonacci(0u) == 0u);ASSERT(fibonacci(1u) == 1u);ASSERT(fibonacci(2u) == 1u);ASSERT(fibonacci(3u) == 2u);...ASSERT(fibonacci(7u) == 13u);ASSERT(fibonacci(8u) == 21u);

• Immutability

• Thread safe

• Easy to test!

3

Page 4: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

OOP

• States

• Dependencies (e.g Strategy pattern)

• Bad patterns -> Side Effects (singleton)

4

Page 5: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

OOP - SOLID

• Loosely coupled system

• Interface (ptr or ref)

5

Page 6: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

UUT/SUT

dependencydependencyReal

Test Double

MockStubFake

Often very heavy, e.g. requires network

Inter-face

Dependency Replacement - DR

Inter-face

6

Page 7: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

Creational Patterns• Factory Method

• Abstract Factory

• Service Locator

• Dependency Injection (DI)

• Extra Constructor / Setter

• DI != Dependency Replacement

7

Page 8: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

Creational Patterns• Factory Method

• Abstract Factory

• Service Locator

• Dependency Injection (DI)

• Extra Constructor / Setter

• DI != Dependency Replacement

• Who owns the object?

• Can we access the object from the test?

7

Page 9: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

OOP - Testing• Replace the dependency

• Access the dependency (private)

• To exercise them

• Make assertions on them

8

Page 10: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

Real

Often very heavy, e.g. requires network

UUT/SUT

dependencydependency

9

Page 11: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

Real

Often very heavy, e.g. requires network

No explicit interface (runtime or ct) What are the options for testing in C++?

UUT/SUT

dependencydependency

9

Page 12: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 4710

Page 13: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

• Linker

• Header only code?

• Templates? (extern template)

• Requires build system support

10

Page 14: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

• Linker

• Header only code?

• Templates? (extern template)

• Requires build system support

• Preprocessor

• Black magic

10

Page 15: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

• Linker

• Header only code?

• Templates? (extern template)

• Requires build system support

• Preprocessor

• Black magic

• Refactor

• Add that interface

10

Page 16: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

Seams

• Link seam

• Preprocessor seam

• Object seam

• Compile seam

With a seam we can alter behaviour in our program without editing the original unit under test.

11

Page 17: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

Seams

• Link seam

• Preprocessor seam

• Object seam

• Compile seam

With a seam we can alter behaviour in our program without editing the original unit under test.

The enabling point of a seam is the place where we can

make the decision to use one behaviour or another.

11

Page 18: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

class Entity {

public:

int process(int i) { int x = …; return x * 42; }

private: …

}; void test1() { Entity e;

ASSERT(e.process(1) == 42);

}

Case study

12

Page 19: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

class Entity {

public:

int process(int i) { int x = …; return x * 42; }

private: …

}; void test1() { Entity e;

ASSERT(e.process(1) == 42);

}

Case study

“Can we make it work in a multithreaded

environment?”

12

Page 20: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

class Entity {

public:

int process(int i) {

if(m.try_lock()) { int x = …; m.unlock(); return x * 42; }

else { …; return 0; }

}

private:

std::mutex m; …};

13

Page 21: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

class Entity {

public:

int process(int i) {

if(m.try_lock()) { int x = …; m.unlock(); return x * 42; }

else { …; return 0; }

}

private:

std::mutex m; …};

13

How to test the new logic?

Page 22: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

struct Mutex { virtual void lock() = 0;

virtual void unlock() = 0;

virtual bool try_lock() = 0;

};

struct RealMutex : Mutex { … };

struct StubMutex : Mutex { bool try_lock_result = false;

virtual bool try_lock() override {

return try_lock_result;

} … };

14

Page 23: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

struct Mutex { virtual void lock() = 0;

virtual void unlock() = 0;

virtual bool try_lock() = 0;

};

struct RealMutex : Mutex { … };

struct StubMutex : Mutex { bool try_lock_result = false;

virtual bool try_lock() override {

return try_lock_result;

} … };

virtual ~Mutex() {}

14

Page 24: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

class Entity {

public:

Entity(Mutex& m) : m(m) {} int process(int i) { … }

private: Mutex& m;

};

Object Seam

15

Page 25: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

class Entity {

public:

Entity(Mutex& m) : m(m) {} int process(int i) { … }

private: Mutex& m;

};

• Ex. of Object Seam: Entity + Mutex • Enabling point: constructor

Object Seam

15

Page 26: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

void realWorldClient() {

RealMutex m;

Entity e(m);

// Real usage of e

}

void testClient() {

// test setup

StubMutex m;

Entity e(m);

m.try_lock_result = false;

ASSERT(e.process(1) == 0);

m.try_lock_result = true;

ASSERT(e.process(1) == 42);

}16

Page 27: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

class Entity {

public:

Entity(Mutex& m) : m(m) {} int process(int i) { … }

private: Mutex& m;

};

Feels so unnatural!

17

Page 28: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

class Entity {

public:

Entity(Mutex& m) : m(m) {} int process(int i) { … }

private: Mutex& m;

}; Ownership?

Feels so unnatural!

17

Page 29: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

class Entity {

public:

Entity(Mutex& m) : m(m) {} int process(int i) { … }

private: Mutex& m;

}; Ownership?Extra ctor/setter

Feels so unnatural!

17

Page 30: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

class Entity {

public:

Entity(Mutex& m) : m(m) {} int process(int i) { … }

private: Mutex& m;

}; Ownership?Extra ctor/setterExtra interface

Virtual functions Cache locality?

Feels so unnatural!

17

Page 31: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

class Entity {

public:

Entity(Mutex& m) : m(m) {} int process(int i) { … }

private: Mutex& m;

}; Ownership?Extra ctor/setterExtra interface

Virtual functions Cache locality?

Pointer semantics Cache locality?

Feels so unnatural!

17

Page 32: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

class Entity {

public:

Entity(Mutex& m) : m(m) {} int process(int i) { … }

private: Mutex& m;

}; Ownership?Extra ctor/setterExtra interface

Virtual functions Cache locality?

Pointer semantics Cache locality?

Type erasure? Can’t spare the virtual calls

Feels so unnatural!

17

Page 33: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

Ownershipclass Entity { public: Entity(std::unique_ptr<Mutex> m) : m(std::move(m)) {} int process(int i) { if(m−>try_lock()) { … } else { … }

} Mutex& getMutex() { return *m.get(); } private: std::unique_ptr<Mutex> m; }; void testClient() { Entity e(std::make_unique<StubMutex>()); auto& m = e.getMutex(); // assertions …

}18

Page 34: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

Ownership OK As before: Extra ctor, virtuals, pointer semantics, etc Extra getter

19

Page 35: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

template <typename Mutex> class Entity { public:

int process(int i) { … }

// Use only from tests Mutex& getMutex() { return m; }

private:

Mutex m;

};

Compile Seam

20

Page 36: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

void realWorldClient() { Entity<std::mutex> e; // Real usage of e

}void testClient() { struct StubMutex{ void lock() {} void unlock() {} bool try_lock_result = false; bool try_lock() { return try_lock_result; } }; Entity<StubMutex> e; auto& m = e.getMutex(); // assertions …

} 21

Page 37: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

void realWorldClient() { Entity<std::mutex> e; // Real usage of e

}void testClient() { struct StubMutex{ void lock() {} void unlock() {} bool try_lock_result = false; bool try_lock() { return try_lock_result; } }; Entity<StubMutex> e; auto& m = e.getMutex(); // assertions …

}

• No inheritance • No virtual functions

21

Page 38: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

Ownership

Locality

No Extra ctor/setter

Extra Interface (compile time)

Extra Getter

Extra Compilation Time

22

Page 39: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

Extra Compilation Time -Combine with Pimpl

// detail/Entity.hpp

namespace detail {

// as before

template <typename Mutex>class Entity { … };

} // detail

23

Page 40: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

// Entity.hppclass Entity {public: Entity(); ~Entity(); int process(int i);private: struct Impl; std::unique_ptr<Impl> pimpl;};

24

Page 41: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

// Entity.cpp

#include “detail/Entity.hpp” using RealEntity = detail::Entity<std::mutex>;struct Entity::Impl : RealEntity { // delegate the consturctors using RealEntity::RealEntity;};

Entity::Entity() : pimpl(std::make_unique<Impl>()) {}Entity::~Entity() = default;int Entity::process(int i) { return pimpl->process(i); } 25

Page 42: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

// Client.cpp#include “Entity.hpp”void realWorldClient() { Entity e; // Real usage of e}

// Test.cpp #include “detail/Entity.hpp”void testClient() { struct StubMutex { … }; detail::Entity<StubMutex> e; // Test code as before}

26

Page 43: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

No extra compile time

But at least two compiles if detail::Entity changes

Entity.cpp

Test.cpp

Extra complexity

Compile Seam + Pimpl

27

Page 44: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

template <typename Mutex> class Entity {public: Mutex& getMutex() { return m; } int process(int i) { … }private: Mutex m;};

class Entity {

public:

int process(int i) { … }

private:

std::mutex m;};

28

Page 45: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

template <typename Mutex> class Entity {public: Mutex& getMutex() { return m; } int process(int i) { … }private: Mutex m;};

class Entity {

public:

int process(int i) { … }

private:

std::mutex m;}; Intrusive

28

Page 46: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

Eliminate the Extra Gettertemplate <typename Mutex> class Entity { …#ifdef TEST Mutex& getMutex() { return m; }#endif …};

29

Page 47: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

Eliminate the Extra Gettertemplate <typename Mutex> class Entity { …#ifdef TEST Mutex& getMutex() { return m; }#endif …};

Worse

Readability

Maintainability29

Page 48: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

#define private public#include "Entity.hpp"#undef private// Test code comes from here

30

Page 49: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

#define private public#include "Entity.hpp"#undef private// Test code comes from here

Undefined behaviour

The order of allocation of non-static data members with different access control is unspecified

Danger, everything included from Entity.hpp is now public

class X {public: int x;private: int y;public: int z;};

xzy

xyz

31

Page 50: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

Eliminate the Extra Getter - Access via a Friend Function

template <typename Mutex> class Entity {public:+ friend Mutex& testFriend(Entity &e); int process(int i) { … }private: Mutex m;};

32

Page 51: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

// Test.cpp struct StubMutex { … };

StubMutex& testFriend(Entity<StubMutex>& e){ return e.m; }

void testClient() { Entity<StubMutex> e; auto &m = testFriend(e); // assertions …}

33

Page 52: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

Eliminate the Extra Getter - Access via a Friend Class

template <typename Mutex> class Entity {public:+ friend struct EntityTestFriend; int process(int i) { … }private: Mutex m;};

34

Page 53: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

// Test.cpp struct StubMutex { … };

struct EntityTestFriend { template<typename Mutex> static auto& getMutex(Entity<Mutex>& e) { return e.m; }}; void testClient() { Entity<StubMutex> e; auto &m = EntityTestFriend::getMutex(e); // assertions …}

35

Page 54: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

class EntityTestFriend { template<typename Mutex> static auto& getMutex(Entity<Mutex>& e) { return e.m; }+ friend void test_try_lock_succeeds();+ friend void test_try_lock_fails();}; void test_try_lock_succeeds() { Entity<StubMutex> e; auto &m = EntityTestFriend::getMutex(e); // assertion …}// …

36

Page 55: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

class EntityTestFriend { template<typename Mutex> static auto& getMutex(Entity<Mutex>& e) { return e.m; }+ friend void test_try_lock_succeeds();+ friend void test_try_lock_fails();}; void test_try_lock_succeeds() { Entity<StubMutex> e; auto &m = EntityTestFriend::getMutex(e); // assertion …}// … • Attorney <—> EntityTestFriend

• Client <—> Entity

36

Page 56: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

template <typename Mutex> class Entity {public: friend struct EntityTestFriend; int process(int i) { … }private: Mutex m;};

class Entity {

public:

int process(int i) { … }

private:

std::mutex m;};

37

Page 57: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

template <typename Mutex> class Entity {public: friend struct EntityTestFriend; int process(int i) { … }private: Mutex m;};

class Entity {

public:

int process(int i) { … }

private:

std::mutex m;}; Intrusive

37

Page 58: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

Eliminate the Extra Getter - Non-intrusive Access

template <typename Mutex> class Entity {public: int process(int i) { … }private: Mutex m;};

38

Page 59: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

// Test.cpp struct StubMutex { … };

ACCESS_PRIVATE_FIELD( Entity<StubMutex>, StubMutex, m)

void test_try_lock_fails() { Entity<StubMutex> e; auto& m = access_private::m(e); m.try_lock_result = false; ASSERT(e.process(1) == 0);}

39

Page 60: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

Access a private static member

class A { static int i;};int A::i = 42;

40

Page 61: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

Access a private static member

class A { static int i;};int A::i = 42;

template struct private_access<&A::i>;

40

Page 62: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

Access a private static member

class A { static int i;};int A::i = 42;

template struct private_access<&A::i>;

template <int* PtrValue> struct private_access { friend int* get() { return PtrValue; }};

40

Page 63: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

Access a private static member

class A { static int i;};int A::i = 42;

template struct private_access<&A::i>;

template <int* PtrValue> struct private_access { friend int* get() { return PtrValue; }};

int* get();

40

Page 64: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

Access a private static member

class A { static int i;};int A::i = 42;

template struct private_access<&A::i>;

template <int* PtrValue> struct private_access { friend int* get() { return PtrValue; }};

int* get();

void usage() { int* i = get(); assert(*i == 42);}

40

Page 65: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

Access a private non-static memberclass A { int i = 42;};

41

Page 66: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

Access a private non-static memberclass A { int i = 42;};

template struct private_access<&A::i>;

41

Page 67: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

Access a private non-static memberclass A { int i = 42;};

template struct private_access<&A::i>;

using PtrType = int A::*;template<PtrType PtrValue> struct private_access { friend PtrType get() { return PtrValue; }};

41

Page 68: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

Access a private non-static memberclass A { int i = 42;};

template struct private_access<&A::i>;

using PtrType = int A::*;template<PtrType PtrValue> struct private_access { friend PtrType get() { return PtrValue; }};

PtrType get();

41

Page 69: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

Access a private non-static memberclass A { int i = 42;};

template struct private_access<&A::i>;

using PtrType = int A::*;template<PtrType PtrValue> struct private_access { friend PtrType get() { return PtrValue; }};

PtrType get();

void usage() { A a; PtrType ip = get(); int& i = a.*ip; assert(i == 42);} 41

Page 70: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

Can access private member fields, functions

Can’t access private types

Can’t access private ctor/dtor

Link error with in-class defined private static const

42

Page 71: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 4743

Page 72: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

Eliminate the Extra Getter - Out-of-class Friend

template <typename Mutex> class Entity { public: int process(int i) { … } private: Mutex m;};

44

Page 73: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

Eliminate the Extra Getter - Out-of-class Friend

template <typename Mutex> class Entity { public: int process(int i) { … } private: Mutex m;};

// Test.cpp friend for(Entity<StubMutex>) void testClient() { Entity<StubMutex> e; auto& m = e.m; // access the private // assertions …}

44

Page 74: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

Clear intentions, self describing code

No cumbersome accessor patterns

Can access all private (types, ctor, …)

Proof-of-concept implementation in clang

Encapsulation (?)

A good language should prevent non-intuitive, accidental failure

“friend for” cannot be accidental

45

Page 75: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

Visionclass Entity { … };

46

Page 76: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

Visionclass Entity { … };

// Test.cpp void testClient() { using EntityUnderTest = test::ReplaceMemberType<Entity, std::mutex, StubMutex>; EntityUnderTest e; auto& m = e.get<StubMutex>(); // assertions … }

46

Page 77: Friendship in Service of Testing · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com Zoltán Porkoláb, gsd@elte.hu 1

/ 47

Thank you!• Gábor Márton

[email protected]

• https://github.com/martong/access_private

• https://github.com/martong/clang/tree/out-of-class_friend_attr

• Questions?

47


Recommended