Moved VERBS back to cli.py
diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py
index 85a0d1d8a78..662e1a94b37 100644
--- a/letsencrypt/cli.py
+++ b/letsencrypt/cli.py
@@ -629,9 +629,13 @@ class HelpfulArgumentParser(object):
     """
 
     def __init__(self, args, plugins, detect_defaults=False):
-
         from letsencrypt import main
-        self.VERBS = main.VERBS
+        self.VERBS = {"auth": main.obtain_cert, "certonly": main.obtain_cert,
+                      "config_changes": main.config_changes, "run": main.run,
+                      "install": main.install, "plugins": main.plugins_cmd,
+                      "renew": renew, "revoke": main.revoke,
+                      "rollback": main.rollback, "everything": main.run}
+
         # List of topics for which additional help can be provided
         HELP_TOPICS = ["all", "security", "paths", "automation", "testing"] + list(self.VERBS)
 
diff --git a/letsencrypt/main.py b/letsencrypt/main.py
index 19636b93e3e..264f7625eba 100644
--- a/letsencrypt/main.py
+++ b/letsencrypt/main.py
@@ -701,15 +701,6 @@ def main(cli_args=sys.argv[1:]):
     return config.func(config, plugins)
 
 
-# Maps verbs/subcommands to the functions that implement them
-# In principle this should live in cli.HelpfulArgumentParser, but
-# due to issues with import cycles and testing, it lives here
-VERBS = {"auth": obtain_cert, "certonly": obtain_cert,
-         "config_changes": config_changes, "everything": run,
-         "install": install, "plugins": plugins_cmd, "renew": cli.renew,
-         "revoke": revoke, "rollback": rollback, "run": run}
-
-
 if __name__ == "__main__":
     err_string = main()
     if err_string:
diff --git a/letsencrypt/tests/cli_test.py b/letsencrypt/tests/cli_test.py
index c5865206d1b..7b901d41034 100644
--- a/letsencrypt/tests/cli_test.py
+++ b/letsencrypt/tests/cli_test.py
@@ -79,7 +79,7 @@ def _call_stdout(self, args):
         return ret, None, stderr, client
 
     def test_no_flags(self):
-        with MockedVerb("run") as mock_run:
+        with mock.patch('letsencrypt.main.run') as mock_run:
             self._call([])
             self.assertEqual(1, mock_run.call_count)
 
@@ -190,7 +190,7 @@ def test_install_abspath(self):
         chain = 'chain'
         fullchain = 'fullchain'
 
-        with MockedVerb('install') as mock_install:
+        with mock.patch('letsencrypt.main.install') as mock_install:
             self._call(['install', '--cert-path', cert, '--key-path', 'key',
                         '--chain-path', 'chain',
                         '--fullchain-path', 'fullchain'])
@@ -248,7 +248,7 @@ def test_configurator_selection(self, mock_exe_exists):
                 unused_config, auth, unused_installer = mock_init.call_args[0]
                 self.assertTrue(isinstance(auth, manual.Authenticator))
 
-        with MockedVerb("certonly") as mock_certonly:
+        with mock.patch('letsencrypt.main.obtain_cert') as mock_certonly:
             self._call(["auth", "--standalone"])
             self.assertEqual(1, mock_certonly.call_count)
 
@@ -321,7 +321,7 @@ def test_certonly_abspath(self):
         chain = 'chain'
         fullchain = 'fullchain'
 
-        with MockedVerb('certonly') as mock_obtaincert:
+        with mock.patch('letsencrypt.main.obtain_cert') as mock_obtaincert:
             self._call(['certonly', '--cert-path', cert, '--key-path', 'key',
                         '--chain-path', 'chain',
                         '--fullchain-path', 'fullchain'])
@@ -900,7 +900,7 @@ def test_read_file(self):
         self.assertEqual(contents, test_contents)
 
     def test_agree_dev_preview_config(self):
-        with MockedVerb('run') as mocked_run:
+        with mock.patch('letsencrypt.main.run') as mocked_run:
             self._call(['-c', test_util.vector_path('cli.ini')])
         self.assertTrue(mocked_run.called)
 
@@ -1010,34 +1010,5 @@ def test_find_duplicative_names(self, unused_makedir):
         self.assertEqual(result, (None, None))
 
 
-class MockedVerb(object):
-    """Simple class that can be used for mocking out verbs/subcommands.
-
-    Storing a dictionary of verbs and the functions that implement them
-    in letsencrypt.cli makes mocking much more complicated. This class
-    can be used as a simple context manager for mocking out verbs in CLI
-    tests. For example:
-
-    with MockedVerb("run") as mock_run:
-        self._call([])
-        self.assertEqual(1, mock_run.call_count)
-
-    """
-    def __init__(self, verb_name):
-        self.verb_dict = main.VERBS
-        self.verb_func = None
-        self.verb_name = verb_name
-
-    def __enter__(self):
-        self.verb_func = self.verb_dict[self.verb_name]
-        mocked_func = mock.MagicMock()
-        self.verb_dict[self.verb_name] = mocked_func
-
-        return mocked_func
-
-    def __exit__(self, unused_type, unused_value, unused_trace):
-        self.verb_dict[self.verb_name] = self.verb_func
-
-
 if __name__ == '__main__':
     unittest.main()  # pragma: no cover

After looking at this more closely, I agree with @pde that `VERBS` is much nicer in `cli.py` than `main.py`. This PR moves it back to `cli.py` and incorporates the testing fixes to make that work. By moving `VERBS` creation into `__init__`, `MockedVerb` isn't necessary at all.
