diff --git a/scrapy/contracts/__init__.py b/scrapy/contracts/__init__.py
index 8315d21d2..de7ac4503 100644
--- a/scrapy/contracts/__init__.py
+++ b/scrapy/contracts/__init__.py
@@ -1,6 +1,7 @@
 import sys
 import re
 from functools import wraps
+from inspect import getmembers
 from unittest import TestCase
 
 from scrapy.http import Request
@@ -17,7 +18,7 @@ class ContractsManager(object):
 
     def tested_methods_from_spidercls(self, spidercls):
         methods = []
-        for key, value in vars(spidercls).items():
+        for key, value in getmembers(spidercls):
             if (callable(value) and value.__doc__ and
                     re.search(r'^\s*@', value.__doc__, re.MULTILINE)):
                 methods.append(key)

Cannot use contracts with inherited callbacks
### Description

If you want to `scrapy check` a spider that has inherited methods, these methods' contracts will be ignored.

### Reproduce

```python
class BaseSpider(Spider):

    def returns_request(self, response):
        """ method which returns request
        @url https://docs.scrapy.org/en/latest/
        @returns requests 1
        """
        return Request('http://scrapy.org', callback=self.returns_item)


class DemoSpider(BaseSpider):
    name = 'demo_spider'
```

And then run `scrapy check`.

You'll get the following output:

```
----------------------------------------------------------------------
Ran 0 contracts in 0.000s

OK
```

### Reason

`ContractsManager.tested_methods_from_spidercls` uses `vars(spidercls).items()` to get methods.

### Solution

Use `inspect.getmembers(spidercls)` instead.
diff --git a/tests/test_contracts.py b/tests/test_contracts.py
index b07cbee1e..322d20c4c 100644
--- a/tests/test_contracts.py
+++ b/tests/test_contracts.py
@@ -101,6 +101,10 @@ class TestSpider(Spider):
         pass
 
 
+class InheritsTestSpider(TestSpider):
+    name = 'inherits_demo_spider'
+
+
 class ContractsManagerTest(unittest.TestCase):
     contracts = [UrlContract, ReturnsContract, ScrapesContract]
 
@@ -202,3 +206,9 @@ class ContractsManagerTest(unittest.TestCase):
 
         self.assertFalse(self.results.failures)
         self.assertTrue(self.results.errors)
+
+    def test_inherited_contracts(self):
+        spider = InheritsTestSpider()
+
+        requests = self.conman.from_spider(spider, self.results)
+        self.assertTrue(requests)

pip install -e .
parse_log_pytest
pytest
pytest
apt-get update apt-get install -y gcc
3.9
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs==25.3.0
Automat==24.8.1
cffi==1.17.1
constantly==23.10.4
cryptography==44.0.2
cssselect==1.3.0
exceptiongroup @ file:///croot/exceptiongroup_1706031385326/work
hyperlink==21.0.0
idna==3.10
incremental==24.7.2
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work
jmespath==1.0.1
lxml==5.3.1
packaging @ file:///croot/packaging_1734472117206/work
parsel==1.10.0
pluggy @ file:///croot/pluggy_1733169602837/work
pyasn1==0.6.1
pyasn1_modules==0.4.2
pycparser==2.22
PyDispatcher==2.0.7
pyOpenSSL==25.0.0
pytest @ file:///croot/pytest_1738938843180/work
queuelib==1.7.0
-e git+https://github.com/scrapy/scrapy.git@8a4e51a19b9710452eacec8f83ed581ba202ec51#egg=Scrapy
service-identity==24.2.0
six==1.17.0
tomli @ file:///opt/conda/conda-bld/tomli_1657175507142/work
Twisted==24.11.0
typing_extensions==4.13.0
w3lib==2.3.1
zope.interface==7.2

name: scrapy
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - exceptiongroup=1.2.0=py39h06a4308_0
  - iniconfig=1.1.1=pyhd3eb1b0_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - packaging=24.2=py39h06a4308_0
  - pip=25.0=py39h06a4308_0
  - pluggy=1.5.0=py39h06a4308_0
  - pytest=8.3.4=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tomli=2.0.1=py39h06a4308_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - attrs==25.3.0
      - automat==24.8.1
      - cffi==1.17.1
      - constantly==23.10.4
      - cryptography==44.0.2
      - cssselect==1.3.0
      - hyperlink==21.0.0
      - idna==3.10
      - incremental==24.7.2
      - jmespath==1.0.1
      - lxml==5.3.1
      - parsel==1.10.0
      - pyasn1==0.6.1
      - pyasn1-modules==0.4.2
      - pycparser==2.22
      - pydispatcher==2.0.7
      - pyopenssl==25.0.0
      - queuelib==1.7.0
      - service-identity==24.2.0
      - six==1.17.0
      - twisted==24.11.0
      - typing-extensions==4.13.0
      - w3lib==2.3.1
      - zope-interface==7.2
prefix: /opt/conda/envs/scrapy

tests/test_contracts.py::ContractsManagerTest::test_inherited_contracts
tests/test_contracts.py::ContractsManagerTest::test_contracts tests/test_contracts.py::ContractsManagerTest::test_errback tests/test_contracts.py::ContractsManagerTest::test_returns tests/test_contracts.py::ContractsManagerTest::test_scrapes
scrapy/contracts/__init__.py
scrapy/contracts/__init__.py