Repository: CleanCut/green

Issue:
Return a fail if no tests are found.
# Summary:
Currently (v2.4.1) `green` creates an empty test suite if no tests are found and then runs that empty suite, returning passing code. This can cause false-positives for CI and should be changed.

## Example:
```
$ python -m green -vvv -s 1 -W -t --run-coverage emap-convert --debug
2016-05-24 15:32:20     DEBUG Attempting to load target 'emap-convert' with file_pattern 'test*.py'
2016-05-24 15:32:20     DEBUG IGNORED exception: No module named 'emap-convert'
2016-05-24 15:32:20     DEBUG Found 0 tests for target 'emap-convert'
2016-05-24 15:32:20     DEBUG No test loading attempts succeeded.  Created an empty test suite.
Coverage.py warning: No data was collected.
Green 2.4.1, Coverage 4.1, Python 3.4.4


Name    Stmts   Miss  Cover
---------------------------
Ran 0 tests in 0.280s

No Tests Found

Build succeeded
```

As you can see, this technically failed because the package/module name was incorrect (it should have been `emap_convert` - note the underscore). However, Green reported a pass.

## Discussion:
I would recommend changing the default action to fail if no tests are found, rather than pass. This might cause issues with some (albeit very odd) usage cases, so perhaps it's prudent to add a CLI option `--empty-suite-passes` or something like that.


Comments:

Patch:
diff --git a/green/result.py b/green/result.py
index f96019d..908bea4 100644
--- a/green/result.py
+++ b/green/result.py
@@ -417,7 +417,7 @@ class GreenTestResult(BaseTestResult):
             if obj_list:
                 stats.append("{}={}".format(name, color_func(str(len(obj_list)))))
         if not stats:
-            self.stream.writeln(self.colors.passing("No Tests Found"))
+            self.stream.writeln(self.colors.failing("No Tests Found"))
         else:
             grade = self.colors.passing('OK')
             if self.errors or self.failures:
@@ -616,4 +616,8 @@ class GreenTestResult(BaseTestResult):
         """
         Tells whether or not the overall run was successful
         """
-        return len(self.all_errors) == 0
+        # fail if no tests are run.
+        if len(self.all_errors) == 0 and len(self.passing) == 0:
+            return False
+        else:
+            return len(self.all_errors) == 0


Test patch:
diff --git a/green/test/test_result.py b/green/test/test_result.py
index 04f97f8..fdaa846 100644
--- a/green/test/test_result.py
+++ b/green/test/test_result.py
@@ -830,6 +830,8 @@ class TestGreenTestResultAdds(unittest.TestCase):
         """
         self.args.verbose = 1
         gtr = GreenTestResult(self.args, GreenStream(self.stream))
+        self.assertEqual(gtr.wasSuccessful(), False)
+        gtr.passing.append('anything')
         self.assertEqual(gtr.wasSuccessful(), True)
         gtr.all_errors.append('anything')
         self.assertEqual(gtr.wasSuccessful(), False)
diff --git a/green/test/test_runner.py b/green/test/test_runner.py
index 5581bd8..86edcc4 100644
--- a/green/test/test_runner.py
+++ b/green/test/test_runner.py
@@ -194,8 +194,10 @@ class TestRun(unittest.TestCase):
         """
         When we don't find any tests, we say so.
         """
-        run(GreenTestSuite(), self.stream, self.args)
+        result = run(GreenTestSuite(), self.stream, self.args)
         self.assertIn('No Tests Found', self.stream.getvalue())
+        self.assertEqual(result.testsRun, 0)
+        self.assertEqual(result.wasSuccessful(), False)
 
     def test_failedSaysSo(self):
         """