Unlike its name may suggest, defensive programming is not a security feature. Its name comes from defending your classes and functions from being used contrary to their original intention. It's not directly related to testing, but it's a great design pattern to use since it improves your code's quality, making your project future-proof.
Defensive programming starts with static typing. If you create a function that handles a custom-defined type as a parameter, you must make sure nobody will call it with some accidental value. A user will have to consciously check what the function expects and prepare the input accordingly.
In C++, we can also leverage type-safety features when we're writing template code. When we're creating a container for our customers' reviews, we could accept a list of any type and copy from it. To get nicer errors and well-crafted checks, we could write the following:
class CustomerReviewStore : public i_customer_review_store...