table: StrategyChoice uses unique_ptr instead of shared_ptr

refs #3164

Change-Id: Id3110f72aab83982b0768e596a04bad9f7336975
diff --git a/daemon/fw/strategy-registry.cpp b/daemon/fw/strategy-registry.cpp
index de86887..49a778f 100644
--- a/daemon/fw/strategy-registry.cpp
+++ b/daemon/fw/strategy-registry.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2015,  Regents of the University of California,
+ * Copyright (c) 2014-2016,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -29,10 +29,10 @@
 namespace nfd {
 namespace fw {
 
-shared_ptr<Strategy>
+unique_ptr<Strategy>
 makeDefaultStrategy(Forwarder& forwarder)
 {
-  return make_shared<BestRouteStrategy2>(ref(forwarder));
+  return make_unique<BestRouteStrategy2>(ref(forwarder));
 }
 
 static std::map<Name, StrategyCreateFunc>&
diff --git a/daemon/fw/strategy-registry.hpp b/daemon/fw/strategy-registry.hpp
index 9f80288..6675004 100644
--- a/daemon/fw/strategy-registry.hpp
+++ b/daemon/fw/strategy-registry.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2015,  Regents of the University of California,
+ * Copyright (c) 2014-2016,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -36,14 +36,14 @@
 
 class Strategy;
 
-shared_ptr<Strategy>
+unique_ptr<Strategy>
 makeDefaultStrategy(Forwarder& forwarder);
 
 void
 installStrategies(Forwarder& forwarder);
 
 
-typedef std::function<shared_ptr<Strategy>(Forwarder&)> StrategyCreateFunc;
+typedef std::function<unique_ptr<Strategy>(Forwarder&)> StrategyCreateFunc;
 
 void
 registerStrategyImpl(const Name& strategyName, const StrategyCreateFunc& createFunc);
@@ -55,7 +55,7 @@
 registerStrategy()
 {
   registerStrategyImpl(S::STRATEGY_NAME,
-                       [] (Forwarder& forwarder) { return make_shared<S>(ref(forwarder)); });
+                       [] (Forwarder& forwarder) { return make_unique<S>(ref(forwarder)); });
 }
 
 /** \brief registers a built-in strategy
diff --git a/daemon/table/strategy-choice.cpp b/daemon/table/strategy-choice.cpp
index 5778237..3c701d4 100644
--- a/daemon/table/strategy-choice.cpp
+++ b/daemon/table/strategy-choice.cpp
@@ -36,11 +36,11 @@
 
 NFD_LOG_INIT("StrategyChoice");
 
-StrategyChoice::StrategyChoice(NameTree& nameTree, shared_ptr<Strategy> defaultStrategy)
+StrategyChoice::StrategyChoice(NameTree& nameTree, unique_ptr<Strategy> defaultStrategy)
   : m_nameTree(nameTree)
   , m_nItems(0)
 {
-  this->setDefaultStrategy(defaultStrategy);
+  this->setDefaultStrategy(std::move(defaultStrategy));
 }
 
 bool
@@ -54,25 +54,27 @@
   }
 }
 
-bool
-StrategyChoice::install(shared_ptr<Strategy> strategy)
+std::pair<bool, Strategy*>
+StrategyChoice::install(unique_ptr<Strategy> strategy)
 {
   BOOST_ASSERT(strategy != nullptr);
-  const Name& strategyName = strategy->getName();
+  Name strategyName = strategy->getName();
+  // copying Name, so that strategyName remains available even if strategy is deallocated
 
-  if (this->hasStrategy(strategyName, true)) {
+  bool isInserted = false;
+  StrategyInstanceTable::iterator it;
+  std::tie(it, isInserted) = m_strategyInstances.emplace(strategyName, std::move(strategy));
+
+  if (!isInserted) {
     NFD_LOG_ERROR("install(" << strategyName << ") duplicate strategyName");
-    return false;
   }
-
-  m_strategyInstances[strategyName] = strategy;
-  return true;
+  return std::make_pair(isInserted, it->second.get());
 }
 
-fw::Strategy*
+Strategy*
 StrategyChoice::getStrategy(const Name& strategyName) const
 {
-  fw::Strategy* candidate = nullptr;
+  Strategy* candidate = nullptr;
   for (auto it = m_strategyInstances.lower_bound(strategyName);
        it != m_strategyInstances.end() && strategyName.isPrefixOf(it->first); ++it) {
     switch (it->first.size() - strategyName.size()) {
@@ -206,19 +208,22 @@
 }
 
 void
-StrategyChoice::setDefaultStrategy(shared_ptr<Strategy> strategy)
+StrategyChoice::setDefaultStrategy(unique_ptr<Strategy> strategy)
 {
-  this->install(strategy);
+  bool isInstalled = false;
+  Strategy* instance = nullptr;
+  std::tie(isInstalled, instance) = this->install(std::move(strategy));
+  BOOST_ASSERT(isInstalled);
 
   auto entry = make_unique<Entry>(Name());
-  entry->setStrategy(*strategy);
+  entry->setStrategy(*instance);
 
   // don't use .insert here, because it will invoke findEffectiveStrategy
   // which expects an existing root entry
   shared_ptr<name_tree::Entry> nte = m_nameTree.lookup(Name());
   nte->setStrategyChoiceEntry(std::move(entry));
   ++m_nItems;
-  NFD_LOG_INFO("setDefaultStrategy " << strategy->getName());
+  NFD_LOG_INFO("setDefaultStrategy " << instance->getName());
 }
 
 static inline void
@@ -241,9 +246,7 @@
 }
 
 void
-StrategyChoice::changeStrategy(Entry& entry,
-                               fw::Strategy& oldStrategy,
-                               fw::Strategy& newStrategy)
+StrategyChoice::changeStrategy(Entry& entry, Strategy& oldStrategy, Strategy& newStrategy)
 {
   if (&oldStrategy == &newStrategy) {
     return;
diff --git a/daemon/table/strategy-choice.hpp b/daemon/table/strategy-choice.hpp
index 7082092..84b1b03 100644
--- a/daemon/table/strategy-choice.hpp
+++ b/daemon/table/strategy-choice.hpp
@@ -46,7 +46,7 @@
 class StrategyChoice : noncopyable
 {
 public:
-  StrategyChoice(NameTree& nameTree, shared_ptr<fw::Strategy> defaultStrategy);
+  StrategyChoice(NameTree& nameTree, unique_ptr<fw::Strategy> defaultStrategy);
 
 public: // available Strategy types
   /** \brief determines if a strategy is installed
@@ -58,11 +58,12 @@
   hasStrategy(const Name& strategyName, bool isExact = false) const;
 
   /** \brief install a strategy
-   *  \return true if installed; false if not installed due to duplicate strategyName
-   *  \note shared_ptr is passed by value because StrategyChoice takes ownership of strategy
+   *  \return if installed, true, and a pointer to the strategy instance;
+   *          if not installed due to duplicate strategyName, false,
+   *          and a pointer to the existing strategy instance
    */
-  bool
-  install(shared_ptr<fw::Strategy> strategy);
+  std::pair<bool, fw::Strategy*>
+  install(unique_ptr<fw::Strategy> strategy);
 
 public: // Strategy Choice table
   /** \brief set strategy of prefix to be strategyName
@@ -92,15 +93,18 @@
   get(const Name& prefix) const;
 
 public: // effective strategy
-  /// get effective strategy for prefix
+  /** \brief get effective strategy for prefix
+   */
   fw::Strategy&
   findEffectiveStrategy(const Name& prefix) const;
 
-  /// get effective strategy for pitEntry
+  /** \brief get effective strategy for pitEntry
+   */
   fw::Strategy&
   findEffectiveStrategy(const pit::Entry& pitEntry) const;
 
-  /// get effective strategy for measurementsEntry
+  /** \brief get effective strategy for measurementsEntry
+   */
   fw::Strategy&
   findEffectiveStrategy(const measurements::Entry& measurementsEntry) const;
 
@@ -136,7 +140,8 @@
     NameTree::const_iterator m_nameTreeIterator;
   };
 
-  /// number of entries stored
+  /** \return number of entries stored
+   */
   size_t
   size() const;
 
@@ -154,7 +159,7 @@
   getStrategy(const Name& strategyName) const;
 
   void
-  setDefaultStrategy(shared_ptr<fw::Strategy> strategy);
+  setDefaultStrategy(unique_ptr<fw::Strategy> strategy);
 
   void
   changeStrategy(Entry& entry,
@@ -168,7 +173,7 @@
   NameTree& m_nameTree;
   size_t m_nItems;
 
-  typedef std::map<Name, shared_ptr<fw::Strategy>> StrategyInstanceTable;
+  typedef std::map<Name, unique_ptr<fw::Strategy>> StrategyInstanceTable;
   StrategyInstanceTable m_strategyInstances;
 };
 
diff --git a/tests/daemon/fw/asf-strategy.t.cpp b/tests/daemon/fw/asf-strategy.t.cpp
index 687b0e2..af584cf 100644
--- a/tests/daemon/fw/asf-strategy.t.cpp
+++ b/tests/daemon/fw/asf-strategy.t.cpp
@@ -87,7 +87,7 @@
   runConsumer()
   {
     topo.addIntervalConsumer(consumer->getClientFace(), PRODUCER_PREFIX, time::seconds(1), 30);
-    this->advanceClocks(time::milliseconds(1), time::seconds(30));
+    this->advanceClocks(time::milliseconds(10), time::seconds(30));
   }
 
 protected:
@@ -143,7 +143,7 @@
   linkAB->recover();
 
   // Advance time to ensure probing is due
-  this->advanceClocks(time::milliseconds(1), time::seconds(10));
+  this->advanceClocks(time::milliseconds(10), time::seconds(10));
 
   runConsumer();
 
diff --git a/tests/daemon/fw/forwarder.t.cpp b/tests/daemon/fw/forwarder.t.cpp
index 7f2bc41..ad2877e 100644
--- a/tests/daemon/fw/forwarder.t.cpp
+++ b/tests/daemon/fw/forwarder.t.cpp
@@ -26,6 +26,7 @@
 #include "fw/forwarder.hpp"
 #include "tests/daemon/face/dummy-face.hpp"
 #include "dummy-strategy.hpp"
+#include "install-strategy.hpp"
 
 #include "tests/test-common.hpp"
 
@@ -386,39 +387,32 @@
   forwarder.addFace(face1);
   forwarder.addFace(face2);
 
-  StrategyChoice& strategyChoice = forwarder.getStrategyChoice();
-  shared_ptr<DummyStrategy> strategyP = make_shared<DummyStrategy>(
-                                        ref(forwarder), "ndn:/strategyP");
-  shared_ptr<DummyStrategy> strategyQ = make_shared<DummyStrategy>(
-                                        ref(forwarder), "ndn:/strategyQ");
-  strategyChoice.install(strategyP);
-  strategyChoice.install(strategyQ);
-  strategyChoice.insert("ndn:/" , strategyP->getName());
-  strategyChoice.insert("ndn:/B", strategyQ->getName());
+  DummyStrategy& strategyP = choose<DummyStrategy>(forwarder, "ndn:/", "ndn:/strategyP");
+  DummyStrategy& strategyQ = choose<DummyStrategy>(forwarder, "ndn:/B", "ndn:/strategyQ");
 
   shared_ptr<Interest> interest1 = makeInterest("ndn:/A/1");
-  strategyP->afterReceiveInterest_count = 0;
-  strategyP->interestOutFace = face2;
+  strategyP.afterReceiveInterest_count = 0;
+  strategyP.interestOutFace = face2;
   forwarder.startProcessInterest(*face1, *interest1);
-  BOOST_CHECK_EQUAL(strategyP->afterReceiveInterest_count, 1);
+  BOOST_CHECK_EQUAL(strategyP.afterReceiveInterest_count, 1);
 
   shared_ptr<Interest> interest2 = makeInterest("ndn:/B/2");
-  strategyQ->afterReceiveInterest_count = 0;
-  strategyQ->interestOutFace = face2;
+  strategyQ.afterReceiveInterest_count = 0;
+  strategyQ.interestOutFace = face2;
   forwarder.startProcessInterest(*face1, *interest2);
-  BOOST_CHECK_EQUAL(strategyQ->afterReceiveInterest_count, 1);
+  BOOST_CHECK_EQUAL(strategyQ.afterReceiveInterest_count, 1);
 
   this->advanceClocks(time::milliseconds(1), time::milliseconds(5));
 
   shared_ptr<Data> data1 = makeData("ndn:/A/1/a");
-  strategyP->beforeSatisfyInterest_count = 0;
+  strategyP.beforeSatisfyInterest_count = 0;
   forwarder.startProcessData(*face2, *data1);
-  BOOST_CHECK_EQUAL(strategyP->beforeSatisfyInterest_count, 1);
+  BOOST_CHECK_EQUAL(strategyP.beforeSatisfyInterest_count, 1);
 
   shared_ptr<Data> data2 = makeData("ndn:/B/2/b");
-  strategyQ->beforeSatisfyInterest_count = 0;
+  strategyQ.beforeSatisfyInterest_count = 0;
   forwarder.startProcessData(*face2, *data2);
-  BOOST_CHECK_EQUAL(strategyQ->beforeSatisfyInterest_count, 1);
+  BOOST_CHECK_EQUAL(strategyQ.beforeSatisfyInterest_count, 1);
 
   shared_ptr<Interest> interest3 = makeInterest("ndn:/A/3");
   interest3->setInterestLifetime(time::milliseconds(30));
@@ -427,11 +421,11 @@
   interest4->setInterestLifetime(time::milliseconds(5000));
   forwarder.startProcessInterest(*face1, *interest4);
 
-  strategyP->beforeExpirePendingInterest_count = 0;
-  strategyQ->beforeExpirePendingInterest_count = 0;
+  strategyP.beforeExpirePendingInterest_count = 0;
+  strategyQ.beforeExpirePendingInterest_count = 0;
   this->advanceClocks(time::milliseconds(10), time::milliseconds(100));
-  BOOST_CHECK_EQUAL(strategyP->beforeExpirePendingInterest_count, 1);
-  BOOST_CHECK_EQUAL(strategyQ->beforeExpirePendingInterest_count, 0);
+  BOOST_CHECK_EQUAL(strategyP.beforeExpirePendingInterest_count, 1);
+  BOOST_CHECK_EQUAL(strategyQ.beforeExpirePendingInterest_count, 0);
 }
 
 BOOST_AUTO_TEST_CASE(IncomingData)
@@ -482,15 +476,8 @@
   forwarder.addFace(face2);
   forwarder.addFace(face3);
 
-  StrategyChoice& strategyChoice = forwarder.getStrategyChoice();
-  shared_ptr<DummyStrategy> strategyP = make_shared<DummyStrategy>(
-                                        ref(forwarder), "ndn:/strategyP");
-  shared_ptr<DummyStrategy> strategyQ = make_shared<DummyStrategy>(
-                                        ref(forwarder), "ndn:/strategyQ");
-  strategyChoice.install(strategyP);
-  strategyChoice.install(strategyQ);
-  strategyChoice.insert("ndn:/" , strategyP->getName());
-  strategyChoice.insert("ndn:/B", strategyQ->getName());
+  DummyStrategy& strategyP = choose<DummyStrategy>(forwarder, "ndn:/", "ndn:/strategyP");
+  DummyStrategy& strategyQ = choose<DummyStrategy>(forwarder, "ndn:/B", "ndn:/strategyQ");
 
   Pit& pit = forwarder.getPit();
 
@@ -503,18 +490,18 @@
   pit2->insertOrUpdateOutRecord(face1, *interest2);
 
   lp::Nack nack1 = makeNack("/A/AYJqayrzF", 562, lp::NackReason::CONGESTION);
-  strategyP->afterReceiveNack_count = 0;
-  strategyQ->afterReceiveNack_count = 0;
+  strategyP.afterReceiveNack_count = 0;
+  strategyQ.afterReceiveNack_count = 0;
   forwarder.onIncomingNack(*face1, nack1);
-  BOOST_CHECK_EQUAL(strategyP->afterReceiveNack_count, 1);
-  BOOST_CHECK_EQUAL(strategyQ->afterReceiveNack_count, 0);
+  BOOST_CHECK_EQUAL(strategyP.afterReceiveNack_count, 1);
+  BOOST_CHECK_EQUAL(strategyQ.afterReceiveNack_count, 0);
 
   lp::Nack nack2 = makeNack("/B/EVyP73ru", 221, lp::NackReason::CONGESTION);
-  strategyP->afterReceiveNack_count = 0;
-  strategyQ->afterReceiveNack_count = 0;
+  strategyP.afterReceiveNack_count = 0;
+  strategyQ.afterReceiveNack_count = 0;
   forwarder.onIncomingNack(*face1, nack2);
-  BOOST_CHECK_EQUAL(strategyP->afterReceiveNack_count, 0);
-  BOOST_CHECK_EQUAL(strategyQ->afterReceiveNack_count, 1);
+  BOOST_CHECK_EQUAL(strategyP.afterReceiveNack_count, 0);
+  BOOST_CHECK_EQUAL(strategyQ.afterReceiveNack_count, 1);
 
   // record Nack on PIT out-record
   pit::OutRecordCollection::iterator outRecord1 = pit1->getOutRecord(*face1);
@@ -524,11 +511,11 @@
 
   // drop if no PIT entry
   lp::Nack nack3 = makeNack("/yEcw5HhdM", 243, lp::NackReason::CONGESTION);
-  strategyP->afterReceiveNack_count = 0;
-  strategyQ->afterReceiveNack_count = 0;
+  strategyP.afterReceiveNack_count = 0;
+  strategyQ.afterReceiveNack_count = 0;
   forwarder.onIncomingNack(*face1, nack3);
-  BOOST_CHECK_EQUAL(strategyP->afterReceiveNack_count, 0);
-  BOOST_CHECK_EQUAL(strategyQ->afterReceiveNack_count, 0);
+  BOOST_CHECK_EQUAL(strategyP.afterReceiveNack_count, 0);
+  BOOST_CHECK_EQUAL(strategyQ.afterReceiveNack_count, 0);
 
   // drop if no out-record
   shared_ptr<Interest> interest4 = makeInterest("/Etab4KpY", 157);
@@ -536,27 +523,27 @@
   pit4->insertOrUpdateOutRecord(face1, *interest4);
 
   lp::Nack nack4a = makeNack("/Etab4KpY", 157, lp::NackReason::CONGESTION);
-  strategyP->afterReceiveNack_count = 0;
-  strategyQ->afterReceiveNack_count = 0;
+  strategyP.afterReceiveNack_count = 0;
+  strategyQ.afterReceiveNack_count = 0;
   forwarder.onIncomingNack(*face2, nack4a);
-  BOOST_CHECK_EQUAL(strategyP->afterReceiveNack_count, 0);
-  BOOST_CHECK_EQUAL(strategyQ->afterReceiveNack_count, 0);
+  BOOST_CHECK_EQUAL(strategyP.afterReceiveNack_count, 0);
+  BOOST_CHECK_EQUAL(strategyQ.afterReceiveNack_count, 0);
 
   // drop if Nonce does not match out-record
   lp::Nack nack4b = makeNack("/Etab4KpY", 294, lp::NackReason::CONGESTION);
-  strategyP->afterReceiveNack_count = 0;
-  strategyQ->afterReceiveNack_count = 0;
+  strategyP.afterReceiveNack_count = 0;
+  strategyQ.afterReceiveNack_count = 0;
   forwarder.onIncomingNack(*face1, nack4b);
-  BOOST_CHECK_EQUAL(strategyP->afterReceiveNack_count, 0);
-  BOOST_CHECK_EQUAL(strategyQ->afterReceiveNack_count, 0);
+  BOOST_CHECK_EQUAL(strategyP.afterReceiveNack_count, 0);
+  BOOST_CHECK_EQUAL(strategyQ.afterReceiveNack_count, 0);
 
   // drop if inFace is multi-access
   pit4->insertOrUpdateOutRecord(face3, *interest4);
-  strategyP->afterReceiveNack_count = 0;
-  strategyQ->afterReceiveNack_count = 0;
+  strategyP.afterReceiveNack_count = 0;
+  strategyQ.afterReceiveNack_count = 0;
   forwarder.onIncomingNack(*face3, nack4a);
-  BOOST_CHECK_EQUAL(strategyP->afterReceiveNack_count, 0);
-  BOOST_CHECK_EQUAL(strategyQ->afterReceiveNack_count, 0);
+  BOOST_CHECK_EQUAL(strategyP.afterReceiveNack_count, 0);
+  BOOST_CHECK_EQUAL(strategyQ.afterReceiveNack_count, 0);
 }
 
 BOOST_AUTO_TEST_CASE(OutgoingNack)
diff --git a/tests/daemon/fw/install-strategy.hpp b/tests/daemon/fw/install-strategy.hpp
new file mode 100644
index 0000000..ec3c848
--- /dev/null
+++ b/tests/daemon/fw/install-strategy.hpp
@@ -0,0 +1,88 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2016,  Regents of the University of California,
+ *                           Arizona Board of Regents,
+ *                           Colorado State University,
+ *                           University Pierre & Marie Curie, Sorbonne University,
+ *                           Washington University in St. Louis,
+ *                           Beijing Institute of Technology,
+ *                           The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NFD_TESTS_DAEMON_FW_INSTALL_STRATEGY_HPP
+#define NFD_TESTS_DAEMON_FW_INSTALL_STRATEGY_HPP
+
+namespace nfd {
+namespace fw {
+class Strategy;
+} // namespace fw
+
+namespace tests {
+
+/** \brief install a strategy to forwarder
+ *  \tparam S strategy type
+ *  \param forwarder the forwarder
+ *  \param args arguments to strategy constructor
+ *  \throw std::bad_cast a strategy with duplicate strategyName is already installed
+ *                       and has an incompatible type
+ *  \return a reference to the strategy
+ */
+template<typename S, typename ...Args>
+typename std::enable_if<std::is_base_of<fw::Strategy, S>::value, S&>::type
+install(Forwarder& forwarder, Args&&... args)
+{
+  auto strategy = make_unique<S>(ref(forwarder), std::forward<Args>(args)...);
+  fw::Strategy* installed = forwarder.getStrategyChoice().install(std::move(strategy)).second;
+  return dynamic_cast<S&>(*installed);
+}
+
+/** \brief install a strategy to forwarder, and choose the strategy for a namespace
+ *  \tparam S strategy type
+ *  \param forwarder the forwarder
+ *  \param prefix namespace to choose the strategy for
+ *  \param args arguments to strategy constructor
+ *  \throw std::bad_cast a strategy with duplicate strategyName is already installed
+ *                       and has an incompatible type
+ *  \return a reference to the strategy
+ */
+template<typename S, typename ...Args>
+typename std::enable_if<std::is_base_of<fw::Strategy, S>::value, S&>::type
+choose(Forwarder& forwarder, const Name& prefix, Args&&... args)
+{
+  S& strategy = install<S>(forwarder, std::forward<Args>(args)...);
+  forwarder.getStrategyChoice().insert(prefix, strategy.getName());
+  return strategy;
+}
+
+/** \brief install a strategy to forwarder, and choose the strategy as default
+ *  \tparam S strategy type
+ *  \param forwarder the forwarder
+ *  \throw std::bad_cast a strategy with duplicate strategyName is already installed
+ *                       and has an incompatible type
+ *  \return a reference to the strategy
+ */
+template<typename S>
+typename std::enable_if<std::is_base_of<fw::Strategy, S>::value, S&>::type
+choose(Forwarder& forwarder)
+{
+  return choose<S>(forwarder, "ndn:/");
+}
+
+} // namespace tests
+} // namespace nfd
+
+#endif // NFD_TESTS_DAEMON_FW_INSTALL_STRATEGY_HPP
diff --git a/tests/daemon/fw/ncc-strategy.t.cpp b/tests/daemon/fw/ncc-strategy.t.cpp
index b624c74..251e3d6 100644
--- a/tests/daemon/fw/ncc-strategy.t.cpp
+++ b/tests/daemon/fw/ncc-strategy.t.cpp
@@ -50,9 +50,8 @@
 {
   LimitedIo limitedIo(this);
   Forwarder forwarder;
-  typedef StrategyTester<NccStrategy> NccStrategyTester;
-  shared_ptr<NccStrategyTester> strategy = make_shared<NccStrategyTester>(ref(forwarder));
-  strategy->afterAction.connect(bind(&LimitedIo::afterOp, &limitedIo));
+  StrategyTester<NccStrategy>& strategy = choose<StrategyTester<NccStrategy>>(forwarder);
+  strategy.afterAction.connect(bind(&LimitedIo::afterOp, &limitedIo));
 
   shared_ptr<DummyFace> face1 = make_shared<DummyFace>();
   shared_ptr<DummyFace> face2 = make_shared<DummyFace>();
@@ -66,10 +65,6 @@
   fibEntry.addNextHop(*face1, 10);
   fibEntry.addNextHop(*face2, 20);
 
-  StrategyChoice& strategyChoice = forwarder.getStrategyChoice();
-  strategyChoice.install(strategy);
-  strategyChoice.insert(Name(), strategy->getName());
-
   Pit& pit = forwarder.getPit();
 
   // first Interest: strategy knows nothing and follows routing
@@ -79,22 +74,22 @@
   shared_ptr<pit::Entry> pitEntry1 = pit.insert(interest1).first;
 
   pitEntry1->insertOrUpdateInRecord(face3, interest1);
-  strategy->afterReceiveInterest(*face3, interest1, pitEntry1);
+  strategy.afterReceiveInterest(*face3, interest1, pitEntry1);
 
   // forwards to face1 because routing says it's best
   // (no io run here: afterReceiveInterest has already sent the Interest)
-  BOOST_REQUIRE_EQUAL(strategy->sendInterestHistory.size(), 1);
-  BOOST_CHECK_EQUAL(strategy->sendInterestHistory[0].outFaceId, face1->getId());
+  BOOST_REQUIRE_EQUAL(strategy.sendInterestHistory.size(), 1);
+  BOOST_CHECK_EQUAL(strategy.sendInterestHistory[0].outFaceId, face1->getId());
 
   // forwards to face2 because face1 doesn't respond
   limitedIo.run(1, time::milliseconds(500), time::milliseconds(10));
-  BOOST_REQUIRE_EQUAL(strategy->sendInterestHistory.size(), 2);
-  BOOST_CHECK_EQUAL(strategy->sendInterestHistory[1].outFaceId, face2->getId());
+  BOOST_REQUIRE_EQUAL(strategy.sendInterestHistory.size(), 2);
+  BOOST_CHECK_EQUAL(strategy.sendInterestHistory[1].outFaceId, face2->getId());
 
   // face2 responds
   shared_ptr<Data> data1p = makeData("ndn:/0Jm1ajrW/%00");
   Data& data1 = *data1p;
-  strategy->beforeSatisfyInterest(pitEntry1, *face2, data1);
+  strategy.beforeSatisfyInterest(pitEntry1, *face2, data1);
   this->advanceClocks(time::milliseconds(10), time::milliseconds(500));
 
   // second Interest: strategy knows face2 is best
@@ -104,19 +99,18 @@
   shared_ptr<pit::Entry> pitEntry2 = pit.insert(interest2).first;
 
   pitEntry2->insertOrUpdateInRecord(face3, interest2);
-  strategy->afterReceiveInterest(*face3, interest2, pitEntry2);
+  strategy.afterReceiveInterest(*face3, interest2, pitEntry2);
 
   // forwards to face2 because it responds previously
   this->advanceClocks(time::milliseconds(1));
-  BOOST_REQUIRE_GE(strategy->sendInterestHistory.size(), 3);
-  BOOST_CHECK_EQUAL(strategy->sendInterestHistory[2].outFaceId, face2->getId());
+  BOOST_REQUIRE_GE(strategy.sendInterestHistory.size(), 3);
+  BOOST_CHECK_EQUAL(strategy.sendInterestHistory[2].outFaceId, face2->getId());
 }
 
 BOOST_AUTO_TEST_CASE(Bug1853)
 {
   Forwarder forwarder;
-  typedef StrategyTester<NccStrategy> NccStrategyTester;
-  shared_ptr<NccStrategyTester> strategy = make_shared<NccStrategyTester>(ref(forwarder));
+  StrategyTester<NccStrategy>& strategy = choose<StrategyTester<NccStrategy>>(forwarder);
 
   shared_ptr<DummyFace> face1 = make_shared<DummyFace>();
   shared_ptr<DummyFace> face2 = make_shared<DummyFace>();
@@ -129,10 +123,6 @@
   fib::Entry& fibEntry = *fib.insert(Name()).first;
   fibEntry.addNextHop(*face1, 10);
 
-  StrategyChoice& strategyChoice = forwarder.getStrategyChoice();
-  strategyChoice.install(strategy);
-  strategyChoice.insert(Name(), strategy->getName());
-
   Pit& pit = forwarder.getPit();
 
   // first Interest: strategy follows routing and forwards to face1
@@ -141,15 +131,15 @@
   shared_ptr<pit::Entry> pitEntry1 = pit.insert(*interest1).first;
 
   pitEntry1->insertOrUpdateInRecord(face3, *interest1);
-  strategy->afterReceiveInterest(*face3, *interest1, pitEntry1);
+  strategy.afterReceiveInterest(*face3, *interest1, pitEntry1);
 
   this->advanceClocks(time::milliseconds(1));
-  BOOST_REQUIRE_EQUAL(strategy->sendInterestHistory.size(), 1);
-  BOOST_CHECK_EQUAL(strategy->sendInterestHistory[0].outFaceId, face1->getId());
+  BOOST_REQUIRE_EQUAL(strategy.sendInterestHistory.size(), 1);
+  BOOST_CHECK_EQUAL(strategy.sendInterestHistory[0].outFaceId, face1->getId());
 
   // face1 responds
   shared_ptr<Data> data1 = makeData("ndn:/nztwIvHX/%00");
-  strategy->beforeSatisfyInterest(pitEntry1, *face1, *data1);
+  strategy.beforeSatisfyInterest(pitEntry1, *face1, *data1);
   this->advanceClocks(time::milliseconds(10), time::milliseconds(500));
 
   // second Interest: bestFace is face1, nUpstreams becomes 0,
@@ -159,7 +149,7 @@
   shared_ptr<pit::Entry> pitEntry2 = pit.insert(*interest2).first;
 
   pitEntry2->insertOrUpdateInRecord(face3, *interest2);
-  strategy->afterReceiveInterest(*face3, *interest2, pitEntry2);
+  strategy.afterReceiveInterest(*face3, *interest2, pitEntry2);
 
   // FIB entry is changed before doPropagate executes
   fibEntry.addNextHop(*face2, 20);
@@ -170,9 +160,8 @@
 {
   LimitedIo limitedIo(this);
   Forwarder forwarder;
-  typedef StrategyTester<NccStrategy> NccStrategyTester;
-  shared_ptr<NccStrategyTester> strategy = make_shared<NccStrategyTester>(ref(forwarder));
-  strategy->afterAction.connect(bind(&LimitedIo::afterOp, &limitedIo));
+  StrategyTester<NccStrategy>& strategy = choose<StrategyTester<NccStrategy>>(forwarder);
+  strategy.afterAction.connect(bind(&LimitedIo::afterOp, &limitedIo));
 
   shared_ptr<DummyFace> face1 = make_shared<DummyFace>();
   shared_ptr<DummyFace> face2 = make_shared<DummyFace>();
@@ -186,10 +175,6 @@
   fibEntry.addNextHop(*face1, 10);
   fibEntry.addNextHop(*face2, 20);
 
-  StrategyChoice& strategyChoice = forwarder.getStrategyChoice();
-  strategyChoice.install(strategy);
-  strategyChoice.insert(Name(), strategy->getName());
-
   Pit& pit = forwarder.getPit();
 
   // first Interest: strategy forwards to face1 and face2
@@ -198,20 +183,20 @@
   shared_ptr<pit::Entry> pitEntry1 = pit.insert(*interest1).first;
 
   pitEntry1->insertOrUpdateInRecord(face3, *interest1);
-  strategy->afterReceiveInterest(*face3, *interest1, pitEntry1);
-  limitedIo.run(2 - strategy->sendInterestHistory.size(),
+  strategy.afterReceiveInterest(*face3, *interest1, pitEntry1);
+  limitedIo.run(2 - strategy.sendInterestHistory.size(),
                 time::milliseconds(2000), time::milliseconds(10));
-  BOOST_REQUIRE_EQUAL(strategy->sendInterestHistory.size(), 2);
-  BOOST_CHECK_EQUAL(strategy->sendInterestHistory[0].outFaceId, face1->getId());
-  BOOST_CHECK_EQUAL(strategy->sendInterestHistory[1].outFaceId, face2->getId());
+  BOOST_REQUIRE_EQUAL(strategy.sendInterestHistory.size(), 2);
+  BOOST_CHECK_EQUAL(strategy.sendInterestHistory[0].outFaceId, face1->getId());
+  BOOST_CHECK_EQUAL(strategy.sendInterestHistory[1].outFaceId, face2->getId());
 
   // face1 responds
   shared_ptr<Data> data1 = makeData("ndn:/seRMz5a6/%00");
-  strategy->beforeSatisfyInterest(pitEntry1, *face1, *data1);
+  strategy.beforeSatisfyInterest(pitEntry1, *face1, *data1);
   pitEntry1->clearInRecords();
   this->advanceClocks(time::milliseconds(10));
   // face2 also responds
-  strategy->beforeSatisfyInterest(pitEntry1, *face2, *data1);
+  strategy.beforeSatisfyInterest(pitEntry1, *face2, *data1);
   this->advanceClocks(time::milliseconds(10));
 
   // second Interest: bestFace should be face 1
@@ -220,21 +205,20 @@
   shared_ptr<pit::Entry> pitEntry2 = pit.insert(*interest2).first;
 
   pitEntry2->insertOrUpdateInRecord(face3, *interest2);
-  strategy->afterReceiveInterest(*face3, *interest2, pitEntry2);
-  limitedIo.run(3 - strategy->sendInterestHistory.size(),
+  strategy.afterReceiveInterest(*face3, *interest2, pitEntry2);
+  limitedIo.run(3 - strategy.sendInterestHistory.size(),
                 time::milliseconds(2000), time::milliseconds(10));
 
-  BOOST_REQUIRE_GE(strategy->sendInterestHistory.size(), 3);
-  BOOST_CHECK_EQUAL(strategy->sendInterestHistory[2].outFaceId, face1->getId());
+  BOOST_REQUIRE_GE(strategy.sendInterestHistory.size(), 3);
+  BOOST_CHECK_EQUAL(strategy.sendInterestHistory[2].outFaceId, face1->getId());
 }
 
 BOOST_AUTO_TEST_CASE(Bug1971)
 {
   LimitedIo limitedIo(this);
   Forwarder forwarder;
-  typedef StrategyTester<NccStrategy> NccStrategyTester;
-  shared_ptr<NccStrategyTester> strategy = make_shared<NccStrategyTester>(ref(forwarder));
-  strategy->afterAction.connect(bind(&LimitedIo::afterOp, &limitedIo));
+  StrategyTester<NccStrategy>& strategy = choose<StrategyTester<NccStrategy>>(forwarder);
+  strategy.afterAction.connect(bind(&LimitedIo::afterOp, &limitedIo));
 
   shared_ptr<DummyFace> face1 = make_shared<DummyFace>();
   shared_ptr<DummyFace> face2 = make_shared<DummyFace>();
@@ -245,10 +229,6 @@
   fib::Entry& fibEntry = *fib.insert(Name()).first;
   fibEntry.addNextHop(*face2, 10);
 
-  StrategyChoice& strategyChoice = forwarder.getStrategyChoice();
-  strategyChoice.install(strategy);
-  strategyChoice.insert(Name(), strategy->getName());
-
   Pit& pit = forwarder.getPit();
 
   // first Interest: strategy forwards to face2
@@ -257,34 +237,33 @@
   shared_ptr<pit::Entry> pitEntry1 = pit.insert(*interest1).first;
 
   pitEntry1->insertOrUpdateInRecord(face1, *interest1);
-  strategy->afterReceiveInterest(*face1, *interest1, pitEntry1);
-  limitedIo.run(1 - strategy->sendInterestHistory.size(),
+  strategy.afterReceiveInterest(*face1, *interest1, pitEntry1);
+  limitedIo.run(1 - strategy.sendInterestHistory.size(),
                 time::milliseconds(2000), time::milliseconds(10));
-  BOOST_REQUIRE_EQUAL(strategy->sendInterestHistory.size(), 1);
-  BOOST_CHECK_EQUAL(strategy->sendInterestHistory[0].outFaceId, face2->getId());
+  BOOST_REQUIRE_EQUAL(strategy.sendInterestHistory.size(), 1);
+  BOOST_CHECK_EQUAL(strategy.sendInterestHistory[0].outFaceId, face2->getId());
 
   // face2 responds
   shared_ptr<Data> data1 = makeData("ndn:/M4mBXCsd");
   data1->setFreshnessPeriod(time::milliseconds(5));
-  strategy->beforeSatisfyInterest(pitEntry1, *face2, *data1);
+  strategy.beforeSatisfyInterest(pitEntry1, *face2, *data1);
   pitEntry1->deleteOutRecord(*face2);
   pitEntry1->clearInRecords();
   this->advanceClocks(time::milliseconds(10));
 
   // similar Interest: strategy should still forward it
   pitEntry1->insertOrUpdateInRecord(face1, *interest1);
-  strategy->afterReceiveInterest(*face1, *interest1, pitEntry1);
-  limitedIo.run(2 - strategy->sendInterestHistory.size(),
+  strategy.afterReceiveInterest(*face1, *interest1, pitEntry1);
+  limitedIo.run(2 - strategy.sendInterestHistory.size(),
                 time::milliseconds(2000), time::milliseconds(10));
-  BOOST_REQUIRE_EQUAL(strategy->sendInterestHistory.size(), 2);
-  BOOST_CHECK_EQUAL(strategy->sendInterestHistory[1].outFaceId, face2->getId());
+  BOOST_REQUIRE_EQUAL(strategy.sendInterestHistory.size(), 2);
+  BOOST_CHECK_EQUAL(strategy.sendInterestHistory[1].outFaceId, face2->getId());
 }
 
 BOOST_AUTO_TEST_CASE(Bug1998)
 {
   Forwarder forwarder;
-  typedef StrategyTester<NccStrategy> NccStrategyTester;
-  shared_ptr<NccStrategyTester> strategy = make_shared<NccStrategyTester>(ref(forwarder));
+  StrategyTester<NccStrategy>& strategy = choose<StrategyTester<NccStrategy>>(forwarder);
 
   shared_ptr<DummyFace> face1 = make_shared<DummyFace>();
   shared_ptr<DummyFace> face2 = make_shared<DummyFace>();
@@ -296,10 +275,6 @@
   fibEntry.addNextHop(*face1, 10); // face1 is top-ranked nexthop
   fibEntry.addNextHop(*face2, 20);
 
-  StrategyChoice& strategyChoice = forwarder.getStrategyChoice();
-  strategyChoice.install(strategy);
-  strategyChoice.insert(Name(), strategy->getName());
-
   Pit& pit = forwarder.getPit();
 
   // Interest comes from face1, which is sole downstream
@@ -307,11 +282,11 @@
   shared_ptr<pit::Entry> pitEntry1 = pit.insert(*interest1).first;
   pitEntry1->insertOrUpdateInRecord(face1, *interest1);
 
-  strategy->afterReceiveInterest(*face1, *interest1, pitEntry1);
+  strategy.afterReceiveInterest(*face1, *interest1, pitEntry1);
 
   // Interest shall go to face2, not loop back to face1
-  BOOST_REQUIRE_EQUAL(strategy->sendInterestHistory.size(), 1);
-  BOOST_CHECK_EQUAL(strategy->sendInterestHistory[0].outFaceId, face2->getId());
+  BOOST_REQUIRE_EQUAL(strategy.sendInterestHistory.size(), 1);
+  BOOST_CHECK_EQUAL(strategy.sendInterestHistory[0].outFaceId, face2->getId());
 }
 
 BOOST_AUTO_TEST_CASE_EXPECTED_FAILURES(PredictionAdjustment, 1)
diff --git a/tests/daemon/fw/topology-tester.hpp b/tests/daemon/fw/topology-tester.hpp
index abb053d..329244b 100644
--- a/tests/daemon/fw/topology-tester.hpp
+++ b/tests/daemon/fw/topology-tester.hpp
@@ -34,6 +34,7 @@
 #include "face/internal-transport.hpp"
 #include "face/face.hpp"
 #include "fw/strategy.hpp"
+#include "install-strategy.hpp"
 #include "tests/test-common.hpp"
 
 namespace nfd {
@@ -175,7 +176,7 @@
   }
 
   /** \brief sets strategy on forwarder \p i
-   *  \tparam the strategy type
+   *  \tparam S the strategy type
    *  \note Test scenario can also access StrategyChoice table directly.
    */
   template<typename S>
@@ -183,10 +184,7 @@
   setStrategy(TopologyNode i, Name prefix = Name("ndn:/"))
   {
     Forwarder& forwarder = this->getForwarder(i);
-    StrategyChoice& strategyChoice = forwarder.getStrategyChoice();
-    shared_ptr<S> strategy = make_shared<S>(ref(forwarder));
-    strategyChoice.install(strategy);
-    strategyChoice.insert(prefix, strategy->getName());
+    choose<S>(forwarder, prefix);
   }
 
   /** \brief makes a link that interconnects two or more forwarders
diff --git a/tests/daemon/mgmt/strategy-choice-manager.t.cpp b/tests/daemon/mgmt/strategy-choice-manager.t.cpp
index 90789a0..5915e3e 100644
--- a/tests/daemon/mgmt/strategy-choice-manager.t.cpp
+++ b/tests/daemon/mgmt/strategy-choice-manager.t.cpp
@@ -31,8 +31,10 @@
 #include "table/name-tree.hpp"
 #include "table/strategy-choice.hpp"
 #include "fw/strategy.hpp"
+
 #include "tests/daemon/face/dummy-face.hpp"
 #include "tests/daemon/fw/dummy-strategy.hpp"
+#include "tests/daemon/fw/install-strategy.hpp"
 
 #include <ndn-cxx/util/random.hpp>
 #include <ndn-cxx/management/nfd-strategy-choice.hpp>
@@ -52,9 +54,9 @@
 
 public:
   void
-  installStrategy(const Name& strategy)
+  installStrategy(const Name& strategyName)
   {
-    m_strategyChoice.install(make_shared<DummyStrategy>(ref(m_forwarder), strategy));
+    install<DummyStrategy>(m_forwarder, strategyName);
   }
 
   const Name&
diff --git a/tests/daemon/mgmt/tables-config-section.t.cpp b/tests/daemon/mgmt/tables-config-section.t.cpp
index 5d9b636..f3cf743 100644
--- a/tests/daemon/mgmt/tables-config-section.t.cpp
+++ b/tests/daemon/mgmt/tables-config-section.t.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2015,  Regents of the University of California,
+ * Copyright (c) 2014-2016,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -26,9 +26,9 @@
 #include "mgmt/tables-config-section.hpp"
 #include "fw/forwarder.hpp"
 
-
 #include "tests/test-common.hpp"
-#include "tests/daemon/fw/dummy-strategy.hpp"
+#include "../fw/dummy-strategy.hpp"
+#include "../fw/install-strategy.hpp"
 
 namespace nfd {
 namespace tests {
@@ -185,10 +185,8 @@
     "  }\n"
     "}\n";
 
-  m_strategyChoice.install(make_shared<DummyStrategy>(ref(m_forwarder),
-                                                      "/localhost/nfd/strategy/test-strategy-a"));
-  m_strategyChoice.install(make_shared<DummyStrategy>(ref(m_forwarder),
-                                                      "/localhost/nfd/strategy/test-strategy-b"));
+  install<DummyStrategy>(m_forwarder, "/localhost/nfd/strategy/test-strategy-a");
+  install<DummyStrategy>(m_forwarder, "/localhost/nfd/strategy/test-strategy-b");
 
   BOOST_REQUIRE_NO_THROW(runConfig(CONFIG, true));
   {
@@ -224,13 +222,8 @@
     "}\n";
 
 
-  auto version1 = make_shared<DummyStrategy>(ref(m_forwarder),
-                                             "/localhost/nfd/strategy/test-strategy-a/%FD%01");
-
-  auto version2 = make_shared<DummyStrategy>(ref(m_forwarder),
-                                             "/localhost/nfd/strategy/test-strategy-a/%FD%02");
-  m_strategyChoice.install(version1);
-  m_strategyChoice.install(version2);
+  install<DummyStrategy>(m_forwarder, "/localhost/nfd/strategy/test-strategy-a/%FD%01");
+  install<DummyStrategy>(m_forwarder, "/localhost/nfd/strategy/test-strategy-a/%FD%02");
 
   BOOST_REQUIRE_NO_THROW(runConfig(CONFIG, true));
   {
@@ -287,8 +280,7 @@
     "}\n";
 
 
-  m_strategyChoice.install(make_shared<DummyStrategy>(ref(m_forwarder),
-                                                      "/localhost/nfd/strategy/test-strategy-a"));
+  install<DummyStrategy>(m_forwarder, "/localhost/nfd/strategy/test-strategy-a");
 
   BOOST_CHECK_THROW(runConfig(CONFIG, true), ConfigFile::Error);
   BOOST_CHECK_THROW(runConfig(CONFIG, false), ConfigFile::Error);
@@ -307,10 +299,8 @@
     "  }\n"
     "}\n";
 
-  m_strategyChoice.install(make_shared<DummyStrategy>(ref(m_forwarder),
-                                                      "/localhost/nfd/strategy/test-strategy-a"));
-  m_strategyChoice.install(make_shared<DummyStrategy>(ref(m_forwarder),
-                                                      "/localhost/nfd/strategy/test-strategy-b"));
+  install<DummyStrategy>(m_forwarder, "/localhost/nfd/strategy/test-strategy-a");
+  install<DummyStrategy>(m_forwarder, "/localhost/nfd/strategy/test-strategy-b");
 
   BOOST_CHECK_THROW(runConfig(CONFIG, true), ConfigFile::Error);
   BOOST_CHECK_THROW(runConfig(CONFIG, false), ConfigFile::Error);
diff --git a/tests/daemon/table/measurements-accessor.t.cpp b/tests/daemon/table/measurements-accessor.t.cpp
index 98a39c3..cab1dbb 100644
--- a/tests/daemon/table/measurements-accessor.t.cpp
+++ b/tests/daemon/table/measurements-accessor.t.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2015,  Regents of the University of California,
+ * Copyright (c) 2014-2016,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -28,6 +28,7 @@
 
 #include "tests/test-common.hpp"
 #include "../fw/dummy-strategy.hpp"
+#include "../fw/install-strategy.hpp"
 
 namespace nfd {
 namespace tests {
@@ -59,24 +60,22 @@
 {
 protected:
   MeasurementsAccessorFixture()
-    : strategy1(make_shared<MeasurementsAccessorTestStrategy>(ref(forwarder), "ndn:/strategy1"))
-    , strategy2(make_shared<MeasurementsAccessorTestStrategy>(ref(forwarder), "ndn:/strategy2"))
+    : strategy1(install<MeasurementsAccessorTestStrategy>(forwarder, "ndn:/strategy1"))
+    , strategy2(install<MeasurementsAccessorTestStrategy>(forwarder, "ndn:/strategy2"))
     , measurements(forwarder.getMeasurements())
-    , accessor1(strategy1->getMeasurementsAccessor())
-    , accessor2(strategy2->getMeasurementsAccessor())
+    , accessor1(strategy1.getMeasurementsAccessor())
+    , accessor2(strategy2.getMeasurementsAccessor())
   {
     StrategyChoice& strategyChoice = forwarder.getStrategyChoice();
-    strategyChoice.install(strategy1);
-    strategyChoice.install(strategy2);
-    strategyChoice.insert("/"   , strategy1->getName());
-    strategyChoice.insert("/A"  , strategy2->getName());
-    strategyChoice.insert("/A/B", strategy1->getName());
+    strategyChoice.insert("/"   , strategy1.getName());
+    strategyChoice.insert("/A"  , strategy2.getName());
+    strategyChoice.insert("/A/B", strategy1.getName());
   }
 
 protected:
   Forwarder forwarder;
-  shared_ptr<MeasurementsAccessorTestStrategy> strategy1;
-  shared_ptr<MeasurementsAccessorTestStrategy> strategy2;
+  MeasurementsAccessorTestStrategy& strategy1;
+  MeasurementsAccessorTestStrategy& strategy2;
   Measurements& measurements;
   MeasurementsAccessor& accessor1;
   MeasurementsAccessor& accessor2;
diff --git a/tests/daemon/table/strategy-choice.t.cpp b/tests/daemon/table/strategy-choice.t.cpp
index 469cb1a..5897981 100644
--- a/tests/daemon/table/strategy-choice.t.cpp
+++ b/tests/daemon/table/strategy-choice.t.cpp
@@ -24,9 +24,10 @@
  */
 
 #include "table/strategy-choice.hpp"
-#include "tests/daemon/fw/dummy-strategy.hpp"
 
 #include "tests/test-common.hpp"
+#include "../fw/dummy-strategy.hpp"
+#include "../fw/install-strategy.hpp"
 
 namespace nfd {
 namespace tests {
@@ -40,13 +41,10 @@
 {
   Forwarder forwarder;
   Name nameP("ndn:/strategy/P");
-  shared_ptr<Strategy> strategyP = make_shared<DummyStrategy>(ref(forwarder), nameP);
+  install<DummyStrategy>(forwarder, nameP);
 
   StrategyChoice& table = forwarder.getStrategyChoice();
 
-  // install
-  BOOST_CHECK_EQUAL(table.install(strategyP), true);
-
   BOOST_CHECK(table.insert("ndn:/", nameP));
   // { '/'=>P }
 
@@ -64,16 +62,11 @@
   Name nameP("ndn:/strategy/P");
   Name nameQ("ndn:/strategy/Q");
   Name nameZ("ndn:/strategy/Z");
-  shared_ptr<Strategy> strategyP = make_shared<DummyStrategy>(ref(forwarder), nameP);
-  shared_ptr<Strategy> strategyQ = make_shared<DummyStrategy>(ref(forwarder), nameQ);
+  install<DummyStrategy>(forwarder, nameP);
+  install<DummyStrategy>(forwarder, nameQ);
 
   StrategyChoice& table = forwarder.getStrategyChoice();
 
-  // install
-  BOOST_CHECK_EQUAL(table.install(strategyP), true);
-  BOOST_CHECK_EQUAL(table.install(strategyQ), true);
-  BOOST_CHECK_EQUAL(table.install(strategyQ), false);
-
   BOOST_CHECK(table.insert("ndn:/", nameP));
   // { '/'=>P }
 
@@ -88,9 +81,8 @@
   BOOST_CHECK_EQUAL(table.findEffectiveStrategy("ndn:/A")  .getName(), nameP);
   BOOST_CHECK_EQUAL(table.findEffectiveStrategy("ndn:/A/B").getName(), nameP);
   // same instance
-  BOOST_CHECK_EQUAL(&table.findEffectiveStrategy("ndn:/"),    strategyP.get());
-  BOOST_CHECK_EQUAL(&table.findEffectiveStrategy("ndn:/A"),   strategyP.get());
-  BOOST_CHECK_EQUAL(&table.findEffectiveStrategy("ndn:/A/B"), strategyP.get());
+  BOOST_CHECK_EQUAL(&table.findEffectiveStrategy("ndn:/"),
+                    &table.findEffectiveStrategy("ndn:/A/B"));
 
   table.erase("ndn:/A"); // no effect
   // { '/'=>P, '/A/B'=>P }
@@ -130,15 +122,14 @@
   Forwarder forwarder;
   Name nameP("ndn:/strategy/P");
   Name nameQ("ndn:/strategy/Q");
-  shared_ptr<Strategy> strategyP = make_shared<DummyStrategy>(ref(forwarder), nameP);
-  shared_ptr<Strategy> strategyQ = make_shared<DummyStrategy>(ref(forwarder), nameQ);
-  StrategyChoice& table = forwarder.getStrategyChoice();
-  table.install(strategyP);
-  table.install(strategyQ);
+  install<DummyStrategy>(forwarder, nameP);
+  install<DummyStrategy>(forwarder, nameQ);
 
   shared_ptr<Data> dataABC = makeData("/A/B/C");
   Name fullName = dataABC->getFullName();
 
+  StrategyChoice& table = forwarder.getStrategyChoice();
+
   BOOST_CHECK(table.insert("/A", nameP));
   BOOST_CHECK(table.insert(fullName, nameQ));
 
@@ -157,11 +148,10 @@
   Forwarder forwarder;
   Name nameP("ndn:/strategy/P");
   Name nameQ("ndn:/strategy/Q");
-  shared_ptr<Strategy> strategyP = make_shared<DummyStrategy>(ref(forwarder), nameP);
-  shared_ptr<Strategy> strategyQ = make_shared<DummyStrategy>(ref(forwarder), nameQ);
+  install<DummyStrategy>(forwarder, nameP);
+  install<DummyStrategy>(forwarder, nameQ);
+
   StrategyChoice& table = forwarder.getStrategyChoice();
-  table.install(strategyP);
-  table.install(strategyQ);
 
   BOOST_CHECK(table.insert("/A", nameP));
   BOOST_CHECK(table.insert("/A/B/C", nameQ));
@@ -183,12 +173,10 @@
   Forwarder forwarder;
   Name nameP("ndn:/strategy/P");
   Name nameQ("ndn:/strategy/Q");
-  shared_ptr<Strategy> strategyP = make_shared<DummyStrategy>(ref(forwarder), nameP);
-  shared_ptr<Strategy> strategyQ = make_shared<DummyStrategy>(ref(forwarder), nameQ);
+  install<DummyStrategy>(forwarder, nameP);
+  install<DummyStrategy>(forwarder, nameQ);
 
   StrategyChoice& table = forwarder.getStrategyChoice();
-  table.install(strategyP);
-  table.install(strategyQ);
 
   table.insert("ndn:/",      nameP);
   table.insert("ndn:/A/B",   nameQ);
@@ -226,16 +214,12 @@
   Forwarder forwarder;
   Name nameP("ndn:/strategy/P");
   Name nameQ("ndn:/strategy/Q");
-  shared_ptr<Strategy> strategyP = make_shared<DummyStrategy>(ref(forwarder), nameP);
-  shared_ptr<Strategy> strategyQ = make_shared<DummyStrategy>(ref(forwarder), nameQ);
+  install<DummyStrategy>(forwarder, nameP);
+  install<DummyStrategy>(forwarder, nameQ);
 
   StrategyChoice& table = forwarder.getStrategyChoice();
   Measurements& measurements = forwarder.getMeasurements();
 
-  // install
-  table.install(strategyP);
-  table.install(strategyQ);
-
   BOOST_CHECK(table.insert("ndn:/", nameP));
   // { '/'=>P }
   measurements.get("ndn:/")     ->getOrCreateStrategyInfo<PStrategyInfo>();
@@ -245,38 +229,36 @@
 
   BOOST_CHECK(table.insert("ndn:/A/B", nameP));
   // { '/'=>P, '/A/B'=>P }
-  BOOST_CHECK( static_cast<bool>(measurements.get("ndn:/")   ->getStrategyInfo<PStrategyInfo>()));
-  BOOST_CHECK( static_cast<bool>(measurements.get("ndn:/A")  ->getStrategyInfo<PStrategyInfo>()));
-  BOOST_CHECK( static_cast<bool>(measurements.get("ndn:/A/B")->getStrategyInfo<PStrategyInfo>()));
-  BOOST_CHECK( static_cast<bool>(measurements.get("ndn:/A/C")->getStrategyInfo<PStrategyInfo>()));
+  BOOST_CHECK(measurements.get("ndn:/")   ->getStrategyInfo<PStrategyInfo>() != nullptr);
+  BOOST_CHECK(measurements.get("ndn:/A")  ->getStrategyInfo<PStrategyInfo>() != nullptr);
+  BOOST_CHECK(measurements.get("ndn:/A/B")->getStrategyInfo<PStrategyInfo>() != nullptr);
+  BOOST_CHECK(measurements.get("ndn:/A/C")->getStrategyInfo<PStrategyInfo>() != nullptr);
 
   BOOST_CHECK(table.insert("ndn:/A", nameQ));
   // { '/'=>P, '/A/B'=>P, '/A'=>Q }
-  BOOST_CHECK( static_cast<bool>(measurements.get("ndn:/")   ->getStrategyInfo<PStrategyInfo>()));
-  BOOST_CHECK(!static_cast<bool>(measurements.get("ndn:/A")  ->getStrategyInfo<PStrategyInfo>()));
-  BOOST_CHECK( static_cast<bool>(measurements.get("ndn:/A/B")->getStrategyInfo<PStrategyInfo>()));
-  BOOST_CHECK(!static_cast<bool>(measurements.get("ndn:/A/C")->getStrategyInfo<PStrategyInfo>()));
+  BOOST_CHECK(measurements.get("ndn:/")   ->getStrategyInfo<PStrategyInfo>() != nullptr);
+  BOOST_CHECK(measurements.get("ndn:/A")  ->getStrategyInfo<PStrategyInfo>() == nullptr);
+  BOOST_CHECK(measurements.get("ndn:/A/B")->getStrategyInfo<PStrategyInfo>() != nullptr);
+  BOOST_CHECK(measurements.get("ndn:/A/C")->getStrategyInfo<PStrategyInfo>() == nullptr);
 
   table.erase("ndn:/A/B");
   // { '/'=>P, '/A'=>Q }
-  BOOST_CHECK( static_cast<bool>(measurements.get("ndn:/")   ->getStrategyInfo<PStrategyInfo>()));
-  BOOST_CHECK(!static_cast<bool>(measurements.get("ndn:/A")  ->getStrategyInfo<PStrategyInfo>()));
-  BOOST_CHECK(!static_cast<bool>(measurements.get("ndn:/A/B")->getStrategyInfo<PStrategyInfo>()));
-  BOOST_CHECK(!static_cast<bool>(measurements.get("ndn:/A/C")->getStrategyInfo<PStrategyInfo>()));
+  BOOST_CHECK(measurements.get("ndn:/")   ->getStrategyInfo<PStrategyInfo>() != nullptr);
+  BOOST_CHECK(measurements.get("ndn:/A")  ->getStrategyInfo<PStrategyInfo>() == nullptr);
+  BOOST_CHECK(measurements.get("ndn:/A/B")->getStrategyInfo<PStrategyInfo>() == nullptr);
+  BOOST_CHECK(measurements.get("ndn:/A/C")->getStrategyInfo<PStrategyInfo>() == nullptr);
 }
 
 BOOST_AUTO_TEST_CASE(EraseNameTreeEntry)
 {
   Forwarder forwarder;
-  NameTree& nameTree = forwarder.getNameTree();
-  StrategyChoice& table = forwarder.getStrategyChoice();
-
   Name nameP("ndn:/strategy/P");
   Name nameQ("ndn:/strategy/Q");
-  shared_ptr<Strategy> strategyP = make_shared<DummyStrategy>(ref(forwarder), nameP);
-  shared_ptr<Strategy> strategyQ = make_shared<DummyStrategy>(ref(forwarder), nameQ);
-  table.install(strategyP);
-  table.install(strategyQ);
+  install<DummyStrategy>(forwarder, nameP);
+  install<DummyStrategy>(forwarder, nameQ);
+
+  NameTree& nameTree = forwarder.getNameTree();
+  StrategyChoice& table = forwarder.getStrategyChoice();
 
   table.insert("ndn:/", nameP);
 
@@ -297,27 +279,38 @@
   Name name4("ndn:/%FD%04");
   Name nameQ("ndn:/strategy/Q");
   Name nameQ5("ndn:/strategy/Q/%FD%05");
-  shared_ptr<Strategy> strategyP1 = make_shared<DummyStrategy>(ref(forwarder), nameP1);
-  shared_ptr<Strategy> strategyP2 = make_shared<DummyStrategy>(ref(forwarder), nameP2);
-  shared_ptr<Strategy> strategy3  = make_shared<DummyStrategy>(ref(forwarder), name3);
-  shared_ptr<Strategy> strategy4  = make_shared<DummyStrategy>(ref(forwarder), name4);
-  shared_ptr<Strategy> strategyQ  = make_shared<DummyStrategy>(ref(forwarder), nameQ);
-  shared_ptr<Strategy> strategyQ5 = make_shared<DummyStrategy>(ref(forwarder), nameQ5);
 
   StrategyChoice& table = forwarder.getStrategyChoice();
 
   // install
-  BOOST_CHECK_EQUAL(table.install(strategyP1), true);
-  BOOST_CHECK_EQUAL(table.install(strategyP1), false);
+  auto strategyP1 = make_unique<DummyStrategy>(ref(forwarder), nameP1);
+  Strategy* instanceP1 = strategyP1.get();
+  auto strategyP1b = make_unique<DummyStrategy>(ref(forwarder), nameP1);
+  auto strategyP2 = make_unique<DummyStrategy>(ref(forwarder), nameP2);
+  auto strategy3 = make_unique<DummyStrategy>(ref(forwarder), name3);
+  auto strategy4 = make_unique<DummyStrategy>(ref(forwarder), name4);
+  auto strategyQ = make_unique<DummyStrategy>(ref(forwarder), nameQ);
+  auto strategyQ5 = make_unique<DummyStrategy>(ref(forwarder), nameQ5);
+
+  bool isInstalled = false;
+  Strategy* installed = nullptr;
+
+  std::tie(isInstalled, installed) = table.install(std::move(strategyP1));
+  BOOST_CHECK_EQUAL(isInstalled, true);
+  BOOST_CHECK_EQUAL(installed, instanceP1);
+  std::tie(isInstalled, installed) = table.install(std::move(strategyP1b));
+  BOOST_CHECK_EQUAL(isInstalled, false);
+  BOOST_CHECK_EQUAL(installed, instanceP1);
+
   BOOST_CHECK_EQUAL(table.hasStrategy(nameP,  false), true);
   BOOST_CHECK_EQUAL(table.hasStrategy(nameP,  true),  false);
   BOOST_CHECK_EQUAL(table.hasStrategy(nameP1, true),  true);
 
-  BOOST_CHECK_EQUAL(table.install(strategyP2), true);
-  BOOST_CHECK_EQUAL(table.install(strategy3),  true);
-  BOOST_CHECK_EQUAL(table.install(strategy4),  true);
-  BOOST_CHECK_EQUAL(table.install(strategyQ),  true);
-  BOOST_CHECK_EQUAL(table.install(strategyQ5), true);
+  BOOST_CHECK_EQUAL(table.install(std::move(strategyP2)).first, true);
+  BOOST_CHECK_EQUAL(table.install(std::move(strategy3)).first, true);
+  BOOST_CHECK_EQUAL(table.install(std::move(strategy4)).first, true);
+  BOOST_CHECK_EQUAL(table.install(std::move(strategyQ)).first, true);
+  BOOST_CHECK_EQUAL(table.install(std::move(strategyQ5)).first, true);
 
   BOOST_CHECK(table.insert("ndn:/", nameQ));
   // exact match, { '/'=>Q }