Friendship in Service of Testing -...

80
/ 47 Friendship in Service of Testing Gábor Márton, [email protected] Zoltán Porkoláb, [email protected] 1

Transcript of Friendship in Service of Testing -...

Page 1: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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 - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 47

Agenda

• Introduction, principals

• Case study (running example)

• Making the example better

• Vision

2

Page 3: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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 - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 47

OOP

• States

• Dependencies (e.g Strategy pattern)

• Bad patterns -> Side Effects (singleton)

4

Page 5: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 47

OOP - SOLID

• Loosely coupled system

• Interface (ptr or ref)

5

Page 6: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 47

UUT/SUT

dependencydependencyProduction

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 - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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 - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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 - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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 - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 47

Production

Often very heavy, e.g. requires network

UUT/SUT

dependencydependency

9

Page 11: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 47

Production

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 - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 4710

Page 13: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 47

• Linker

• Inline code?

• Header only code?

• Templates?

• Requires build system support

10

Page 14: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 47

• Linker

• Inline code?

• Header only code?

• Templates?

• Requires build system support

• Preprocessor

• namespaces?

10

Page 15: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 47

• Linker

• Inline code?

• Header only code?

• Templates?

• Requires build system support

• Preprocessor

• namespaces?

• Refactor

• Add that interface

10

Page 16: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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 - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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 - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 47

class Entity {

public:

int process(int i) { return accumulate(v.begin(),v.end(),i); }

void add(int i) { v.push_back(i); }

private: vector<int> v;

}; void test1() { Entity e;

e.add(1); e.add(2);

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

}

Case study

12

Page 19: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 47

class Entity {

public:

int process(int i) { return accumulate(v.begin(),v.end(),i); }

void add(int i) { v.push_back(i); }

private: vector<int> v;

}; void test1() { Entity e;

e.add(1); e.add(2);

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

}

Case study

“Can we make it work in a multithreaded

environment?”

12

Page 20: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 47

class Entity {

public:

int process(int i) {

if(m.try_lock()) {

auto result = std::accumulate(...);

m.unlock();

return result; }

else { return -1; }

}

private:

std::mutex m; …};

13

Page 21: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 47

class Entity {

public:

int process(int i) {

if(m.try_lock()) {

auto result = std::accumulate(...);

m.unlock();

return result; }

else { return -1; }

}

private:

std::mutex m; …};

13

How to test the new logic?

Page 22: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 4714

class Entity {public: // Add a constructor // Doesn't compile and bad Entity(const std::mutex& m) : m(m) {} int process(int i) { if(m.try_lock()) { ... } else { ... } } ...private: std::mutex m; ...};

DR - Add a constructor

Page 23: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 4715

class Entity {public: // Let's assume that std::mutex is // copyable Entity(std::mutex m) : m(m) {} int process(int i) {...} ...private: std::mutex m; ...};

Page 24: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 4716

void test() { std::mutex m; // if std::mutex would be copyable Entity e(std::reference_wrapper<std::mutex>(m)); // set up m, that try_lock will fail set_try_lock_fails(m); // ??? ASSERT_EQUAL(m.process(1), -1);}

Page 25: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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;

} … };

17

Page 26: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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() {}

17

Page 27: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 47

class Entity {

public:

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

private: Mutex& m;

};

Object Seam

18

Page 28: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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

18

Page 29: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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) == -1);

m.try_lock_result = true;

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

}19

Page 30: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 47

class Entity {

public:

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

private: Mutex& m;

};

Feels so unnatural!

20

Page 31: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 47

class Entity {

public:

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

private: Mutex& m;

}; Ownership?

Feels so unnatural!

20

Page 32: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 47

class Entity {

public:

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

private: Mutex& m;

}; Ownership?Extra ctor/setter

Feels so unnatural!

20

Page 33: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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!

20

Page 34: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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!

20

Page 35: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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!

20

Page 36: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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 …

}21

Page 37: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 47

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

22

Page 38: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 47

template <typename Mutex> class Entity { public:

int process(int i) { … }

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

private:

Mutex m;

};

Compile Seam

23

Page 39: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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 …

} 24

Page 40: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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

24

Page 41: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 47

Ownership

Locality

No Extra ctor/setter

Extra Interface (compile time)

Extra Getter

Extra Compilation Time

25

Page 42: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 47

Extra Compilation Time -Combine with Pimpl

// detail/Entity.hpp

namespace detail {

// as before

template <typename Mutex>class Entity { … };

} // detail

26

Page 43: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 47

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

27

Page 44: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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); } 28

Page 45: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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}

29

Page 46: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 47

No extra compile time

But at least two compiles if detail::Entity changes

Entity.cpp

Test.cpp

Extra complexity

Compile Seam + Pimpl

30

Page 47: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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;};

31

Page 48: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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

31

Page 49: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 47

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

32

Page 50: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 47

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

Worse

Readability

Maintainability32

Page 51: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 47

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

33

Page 52: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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

34

Page 53: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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;};

35

Page 54: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 47

// Test.cpp struct StubMutex { … };

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

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

36

Page 55: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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;};

37

Page 56: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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 …}

38

Page 57: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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 …}// …

39

Page 58: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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

39

Page 59: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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;};

40

Page 60: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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

40

Page 61: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 47

Eliminate the Extra Getter - Non-intrusive Access

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

41

Page 62: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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) == -1);}

42

Page 63: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 47

Access a private static member

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

43

Page 64: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 47

Access a private static member

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

template struct private_access<&A::i>;

43

Page 65: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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; }};

43

Page 66: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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();

43

Page 67: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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);}

43

Page 68: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 47

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

44

Page 69: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 47

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

template struct private_access<&A::i>;

44

Page 70: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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; }};

44

Page 71: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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();

44

Page 72: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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);} 44

Page 73: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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

45

Page 74: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 4746

Page 75: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 47

Eliminate the Extra Getter - Out-of-class Friend

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

47

Page 76: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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 …}

47

Page 77: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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

48

Page 78: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 47

Visionclass Entity { … };

49

Page 79: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 47

Visionclass Entity { … };

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

49

Page 80: Friendship in Service of Testing - gsd.web.elte.hugsd.web.elte.hu/lectures/bolyai/2016/friends/ooc-bolyai.pdf · / 47 Friendship in Service of Testing Gábor Márton, martongabesz@gmail.com

/ 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?

50