{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Test-Driven Development (TDD)\n",
    "\n",
    "## Advantages of TDD\n",
    "The process of writing a test that encodes a requirement before implement-ing the solution is the fundamental idea behind TDD. Proponents say that code written this way tends to be more modular, robust, clean, and well designed. Writing good tests is the best way to document your code for other developers. A good test suite is a fully working set of examples that never gets out of sync. It protects against regressions in functionality whenever you add new features.\n",
    "\n",
    "Unit tests also serve as a fantastic way to submit bug reports by writing a unit test that fails. Once the bug is fi xed, it will stay fi xed because the unit test and the code that fi xes the bug become part of the test suite.\n",
    "\n",
    "## Red-Green-Refactor\n",
    "Red-Green-Refactor TDD practitioners have a mantra: red, green, refactor. Red is the fi rst step, and it means to implement a failing test. This is done for several reasons, principal of which is to make sure you’re actually testing something. You might be surprised how common it is to accidentally design a test that doesn’t make any assertions. Next, you implement code that makes the test pass. \n",
    "\n",
    "No more, no less. This turns the test from red to green. Now that you have working code and a passing test, you can refactor your production code.  To refactor means to restructure existing code without changing its func-tionality. For example, you might fi nd a more elegant way to write the same code, replace your code with a third-party library, or rewrite your code to have better performance characteristics.\n",
    "\n",
    "If you accidentally break something, you’ll know immediately because your test suite will tell you. Then you continue to implement the remainder of the class using TDD. You can work on the collision threshold next."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Writing a Skeleton AutoBrake Class\n",
    "\n",
    "A subtle but important feature of unit tests is that if you don’t care about some dependency of the unit under test, you can just provide an empty implementation that performs some innocuous, default behavior. This empty implementation is sometimes called a stub."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "struct SpeedUpdate {\n",
    "    double velocity_mps;\n",
    "};\n",
    "\n",
    "struct CarDetected {\n",
    "    double distance_m;\n",
    "    double velocity_mps;\n",
    "};\n",
    "\n",
    "struct BrakeCommand {\n",
    "    double time_to_collision_s;\n",
    "};"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "template <typename T>\n",
    "struct AutoBrake {\n",
    "    public:\n",
    "        AutoBrake(const T& publish) : publish{ publish } {}\n",
    "        void observe(const SpeedUpdate& cd) {}\n",
    "        void observe(const CarDetected& cd) {}\n",
    "        void set_collision_threshold_s(double x) {\n",
    "            collision_threshold_s = x;\n",
    "        }\n",
    "        double get_collision_threshold_s() const {\n",
    "            return collision_threshold_s;\n",
    "        }\n",
    "        double get_speed_mps() const {\n",
    "            return speed_mps;\n",
    "        }\n",
    "    private:\n",
    "        double collision_threshold_s;\n",
    "        double speed_mps;\n",
    "        const T& publish;\n",
    "};"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Assertions: The Building Blocks of Unit Tests"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "#include <stdexcept>\n",
    "\n",
    "constexpr void assert_that(bool statement, const char* message) {\n",
    "    if (!statement) throw std::runtime_error{ message };\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "assert_that(1+2>2, \"This test will be passed\");"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "ename": "Standard Exception",
     "evalue": "This test will not",
     "output_type": "error",
     "traceback": [
      "Standard Exception: This test will not"
     ]
    }
   ],
   "source": [
    "assert_that(1+1==3, \"This test will not\");"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Requirement: Initial Speed Is Zero"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "void initial_speed_is_zero() {\n",
    "    AutoBrake auto_brake{ [](const BrakeCommand&){} };\n",
    "    assert_that(auto_brake.get_speed_mps() == 0L, \"Speed not equal 0\");\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "ename": "Standard Exception",
     "evalue": "Speed not equal 0",
     "output_type": "error",
     "traceback": [
      "Standard Exception: Speed not equal 0"
     ]
    }
   ],
   "source": [
    "initial_speed_is_zero();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> yingshaoxo: I didn't see anything fun from the building of a cpp program. It's too stupid compared to Javascript, Python, Java, Go..."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "C++17",
   "language": "C++17",
   "name": "xcpp17"
  },
  "language_info": {
   "codemirror_mode": "text/x-c++src",
   "file_extension": ".cpp",
   "mimetype": "text/x-c++src",
   "name": "c++",
   "version": "17"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
