Repository: scrapy/scrapy

Issue:
scrapy check command ignores contracts with the same URL
### Description
When testing callbacks with the same URL, only one callback is tested.

### Reproduce
```python
class DemoSpider(Spider):
    name = 'demo_spider'

    def returns_item_with_url(self, response):
        """ method which returns request
        @url http://scrapy.org
        @returns items 1 1
        """
        return TestItem(url=response.url)

    def returns_item_with_name(self, response):
        """ method which returns request
        @url http://scrapy.org
        @returns items 1 1
        """
        return TestItem(name='scrapy')
```

Then run `scrapy check`.

You'll get the following output:

```
.
----------------------------------------------------------------------
Ran 1 contract in 0.894s

OK
```

### Reason
This is default behavior for crawlers to filter same URLs.

### Solution
Use `dont_filter` in requests returned by `ContractsManager`.


Discussion:

Resolving patch:
diff --git a/scrapy/contracts/__init__.py b/scrapy/contracts/__init__.py
--- a/scrapy/contracts/__init__.py
+++ b/scrapy/contracts/__init__.py
@@ -56,7 +56,12 @@ def from_method(self, method, results):
 
             # calculate request args
             args, kwargs = get_spec(request_cls.__init__)
+
+            # Don't filter requests to allow
+            # testing different callbacks on the same URL.
+            kwargs['dont_filter'] = True
             kwargs['callback'] = method
+
             for contract in contracts:
                 kwargs = contract.adjust_request_args(kwargs)
 


Test patch:
diff --git a/tests/test_contracts.py b/tests/test_contracts.py
--- a/tests/test_contracts.py
+++ b/tests/test_contracts.py
@@ -1,9 +1,12 @@
 from unittest import TextTestResult
 
+from six import get_unbound_function
+from twisted.internet import defer
 from twisted.python import failure
 from twisted.trial import unittest
 
 from scrapy import FormRequest
+from scrapy.crawler import CrawlerRunner
 from scrapy.spidermiddlewares.httperror import HttpError
 from scrapy.spiders import Spider
 from scrapy.http import Request
@@ -14,6 +17,7 @@
     ReturnsContract,
     ScrapesContract,
 )
+from tests.mockserver import MockServer
 
 
 class TestItem(Item):
@@ -198,14 +202,12 @@ def test_scrapes(self):
         self.should_succeed()
 
         # scrapes_item_fail
-        request = self.conman.from_method(spider.scrapes_item_fail,
-                self.results)
+        request = self.conman.from_method(spider.scrapes_item_fail, self.results)
         request.callback(response)
         self.should_fail()
 
         # scrapes_dict_item_fail
-        request = self.conman.from_method(spider.scrapes_dict_item_fail,
-                self.results)
+        request = self.conman.from_method(spider.scrapes_dict_item_fail, self.results)
         request.callback(response)
         self.should_fail()
 
@@ -224,6 +226,38 @@ def test_errback(self):
         self.assertFalse(self.results.failures)
         self.assertTrue(self.results.errors)
 
+    @defer.inlineCallbacks
+    def test_same_url(self):
+
+        class TestSameUrlSpider(Spider):
+            name = 'test_same_url'
+
+            def __init__(self, *args, **kwargs):
+                super(TestSameUrlSpider, self).__init__(*args, **kwargs)
+                self.visited = 0
+
+            def start_requests(s):
+                return self.conman.from_spider(s, self.results)
+
+            def parse_first(self, response):
+                self.visited += 1
+                return TestItem()
+
+            def parse_second(self, response):
+                self.visited += 1
+                return TestItem()
+
+        with MockServer() as mockserver:
+            contract_doc = '@url {}'.format(mockserver.url('/status?n=200'))
+
+            get_unbound_function(TestSameUrlSpider.parse_first).__doc__ = contract_doc
+            get_unbound_function(TestSameUrlSpider.parse_second).__doc__ = contract_doc
+
+            crawler = CrawlerRunner().create_crawler(TestSameUrlSpider)
+            yield crawler.crawl()
+
+        self.assertEqual(crawler.spider.visited, 2)
+
     def test_form_contract(self):
         spider = TestSpider()
         request = self.conman.from_method(spider.custom_form, self.results)