friendship in service of testing -...
TRANSCRIPT
![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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/1.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/2.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/3.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/4.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/5.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/6.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/7.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/8.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/9.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/10.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/11.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/12.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/13.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/14.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/15.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/16.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/17.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/18.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/19.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/20.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/21.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/22.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/23.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/24.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/25.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/26.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/27.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/28.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/29.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/30.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/31.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/32.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/33.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/34.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/35.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/36.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/37.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/38.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/39.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/40.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/41.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/42.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/43.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/44.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/45.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/46.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/47.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/48.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/49.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/50.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/51.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/52.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/53.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/54.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/55.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/56.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/57.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/58.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/59.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/60.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/61.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/62.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/63.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/64.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/65.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/66.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/67.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/68.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/69.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/70.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/71.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/72.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/73.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/74.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/75.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/76.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/77.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/78.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/79.jpg)
/ 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](https://reader033.vdocuments.site/reader033/viewer/2022050504/5f96444db756045216202858/html5/thumbnails/80.jpg)
/ 47
Thank you!• Gábor Márton
• https://github.com/martong/access_private
• https://github.com/martong/clang/tree/out-of-class_friend_attr
• Questions?
50