estimator_checks_generator does not return (estimator, check) when hitting an expected failed check

### Describe the bug

Currently running sklearn_check_generator with mark="skip" on our estimators.

https://scikit-learn.org/stable/modules/generated/sklearn.utils.estimator_checks.estimator_checks_generator.html

I would like to start running those checks with "xfail".

But when I do so any test 'marked' via the `expected_failed_checks` dictionary gives a 
`ValueError: too many values to unpack (expected 2)`

### Steps/Code to Reproduce

```python
from sklearn.utils.estimator_checks import estimator_checks_generator
from sklearn.base import BaseEstimator

expected_failed_checks = {"check_complex_data": "some reason"}

estimator = BaseEstimator()

# fine
for e, check in estimator_checks_generator(
                estimator=estimator,
                expected_failed_checks=expected_failed_checks, 
                mark="skip"
            ):
    print(check)

# error
for e, check in estimator_checks_generator(
                estimator=estimator,
                expected_failed_checks=expected_failed_checks, 
                mark="xfail"
            ):
    print(check)
```

### Expected Results

estimator_checks_generator to yield (estimator, check) tuples whether xfail or skip was requested

### Actual Results

```
functools.partial(<function check_estimator_cloneable at 0x7ec1883e5120>, 'BaseEstimator')
functools.partial(<function check_estimator_cloneable at 0x7ec1883e5120>, 'BaseEstimator')
functools.partial(<function check_estimator_tags_renamed at 0x7ec1883e62a0>, 'BaseEstimator')
functools.partial(<function check_valid_tag_types at 0x7ec1883e6200>, 'BaseEstimator')
functools.partial(<function check_estimator_repr at 0x7ec1883e51c0>, 'BaseEstimator')
functools.partial(<function check_no_attributes_set_in_init at 0x7ec1883e4b80>, 'BaseEstimator')
functools.partial(<function check_fit_score_takes_y at 0x7ec1883da0c0>, 'BaseEstimator')
functools.partial(<function check_estimators_overwrite_params at 0x7ec1883e4a40>, 'BaseEstimator')
functools.partial(<function check_dont_overwrite_parameters at 0x7ec1883d8e00>, 'BaseEstimator')
functools.partial(<function check_estimators_fit_returns_self at 0x7ec1883dbb00>, 'BaseEstimator')
functools.partial(<function check_readonly_memmap_input at 0x7ec1883dbc40>, 'BaseEstimator')
functools.partial(<function check_estimators_unfitted at 0x7ec1883dbd80>, 'BaseEstimator')
functools.partial(<function check_do_not_raise_errors_in_init_or_set_params at 0x7ec1883e6d40>, 'BaseEstimator')
functools.partial(<function check_n_features_in_after_fitting at 0x7ec1883e6160>, 'BaseEstimator')
functools.partial(<function check_mixin_order at 0x7ec1883d9f80>, 'BaseEstimator')
functools.partial(<function check_positive_only_tag_during_fit at 0x7ec1883e54e0>, 'BaseEstimator')
functools.partial(<function check_estimators_dtypes at 0x7ec1883da200>, 'BaseEstimator')
<function _maybe_mark.<locals>.wrapped at 0x7ec20dbda2a0>
functools.partial(<function check_dtype_object at 0x7ec1883d8a40>, 'BaseEstimator')
functools.partial(<function check_estimators_empty_data_messages at 0x7ec1883da3e0>, 'BaseEstimator')
functools.partial(<function check_pipeline_consistency at 0x7ec1883d9e40>, 'BaseEstimator')
functools.partial(<function check_estimators_nan_inf at 0x7ec1883da520>, 'BaseEstimator')
functools.partial(<function check_estimator_sparse_tag at 0x7ec1883bbe20>, 'BaseEstimator')
functools.partial(<function check_estimator_sparse_array at 0x7ec1883d8040>, 'BaseEstimator')
functools.partial(<function check_estimator_sparse_matrix at 0x7ec1883bbf60>, 'BaseEstimator')
functools.partial(<function check_estimators_pickle at 0x7ec1883da7a0>, 'BaseEstimator')
functools.partial(<function check_estimators_pickle at 0x7ec1883da7a0>, 'BaseEstimator', readonly_memmap=True)
functools.partial(<function check_f_contiguous_array_estimator at 0x7ec1883d80e0>, 'BaseEstimator')
functools.partial(<function check_parameters_default_constructible at 0x7ec1883e5260>, 'BaseEstimator')
functools.partial(<function check_methods_sample_order_invariance at 0x7ec1883d9260>, 'BaseEstimator')
functools.partial(<function check_methods_subset_invariance at 0x7ec1883d9120>, 'BaseEstimator')
functools.partial(<function check_fit2d_1sample at 0x7ec1883d9440>, 'BaseEstimator')
functools.partial(<function check_fit2d_1feature at 0x7ec1883d9620>, 'BaseEstimator')
functools.partial(<function check_get_params_invariance at 0x7ec1883e58a0>, 'BaseEstimator')
functools.partial(<function check_set_params at 0x7ec1883e59e0>, 'BaseEstimator')
functools.partial(<function check_dict_unchanged at 0x7ec1883d8c20>, 'BaseEstimator')
functools.partial(<function check_fit_idempotent at 0x7ec1883e5e40>, 'BaseEstimator')
functools.partial(<function check_fit_check_is_fitted at 0x7ec1883e5ee0>, 'BaseEstimator')
functools.partial(<function check_n_features_in at 0x7ec1883e5f80>, 'BaseEstimator')
functools.partial(<function check_fit1d at 0x7ec1883d9760>, 'BaseEstimator')
functools.partial(<function check_fit2d_predict1d at 0x7ec1883d8f40>, 'BaseEstimator')
functools.partial(<function check_estimator_cloneable at 0x7ec1883e5120>, 'BaseEstimator')
functools.partial(<function check_estimator_cloneable at 0x7ec1883e5120>, 'BaseEstimator')
functools.partial(<function check_estimator_tags_renamed at 0x7ec1883e62a0>, 'BaseEstimator')
functools.partial(<function check_valid_tag_types at 0x7ec1883e6200>, 'BaseEstimator')
functools.partial(<function check_estimator_repr at 0x7ec1883e51c0>, 'BaseEstimator')
functools.partial(<function check_no_attributes_set_in_init at 0x7ec1883e4b80>, 'BaseEstimator')
functools.partial(<function check_fit_score_takes_y at 0x7ec1883da0c0>, 'BaseEstimator')
functools.partial(<function check_estimators_overwrite_params at 0x7ec1883e4a40>, 'BaseEstimator')
functools.partial(<function check_dont_overwrite_parameters at 0x7ec1883d8e00>, 'BaseEstimator')
functools.partial(<function check_estimators_fit_returns_self at 0x7ec1883dbb00>, 'BaseEstimator')
functools.partial(<function check_readonly_memmap_input at 0x7ec1883dbc40>, 'BaseEstimator')
functools.partial(<function check_estimators_unfitted at 0x7ec1883dbd80>, 'BaseEstimator')
functools.partial(<function check_do_not_raise_errors_in_init_or_set_params at 0x7ec1883e6d40>, 'BaseEstimator')
functools.partial(<function check_n_features_in_after_fitting at 0x7ec1883e6160>, 'BaseEstimator')
functools.partial(<function check_mixin_order at 0x7ec1883d9f80>, 'BaseEstimator')
functools.partial(<function check_positive_only_tag_during_fit at 0x7ec1883e54e0>, 'BaseEstimator')
functools.partial(<function check_estimators_dtypes at 0x7ec1883da200>, 'BaseEstimator')
Traceback (most recent call last):
  File "/home/remi-gau/github/nilearn/nilearn/tmp/sk.py", line 17, in <module>
    for e, check in estimator_checks_generator(
        ^^^^^^^^
ValueError: too many values to unpack (expected 2)
```

### Versions

```shell
checked from 1.6.0 to 1.7.0rc1
```

COMMENT:
Could you explain a bit what you are trying to do? Or asked differently: how did you end up using `estimator_checks_generator`?

After thinking about this for a bit I think `estimator_checks_generator` should really only be used to construct things like [`parametrize_with_checks`](https://scikit-learn.org/stable/modules/generated/sklearn.utils.estimator_checks.parametrize_with_checks.html) or `check_estimator()` but not by itself. This means we should update the docstring to point people to those two as well as fix the return value.

The reason your example fails is because `estimator_checks_generator` will return a `pytest.param` when `mark="xfail"` in order to have the test marked as XFAIL within pytest. This means it doesn't (always) return `(estimator, check)` tuples. I investigated if we could use a different approach but couldn't find a simple way that would replicate the pytest xfail behaviour. In particular when you have a test that is marked as "expected to fail" but that passes. Which makes me think that is best used for building things like `parametrize_with_checks` instead of explicit `for` loops.

Labels: Bug, Needs Investigation