REF: Base class for all extension tests
State: closed

Added the staticmethods

- assert_series_equal
- assert_frame_equal

to the base class. Useful for test cases like DecimalArray with NaNs,
since our assert_*_equal methods don't properly handle Decimal NaNs.

- [x] tests added / passed
- [x] passes `git diff upstream/master -u -- "*.py" | flake8 --diff`



Labels:
name: Refactor
description: Internal refactoring of code
name: Testing
description: pandas testing functions or related to the test suite
name: Internals
description: Related to non-user accessible pandas implementation

Comments:
> wouldn't it be better to use that as the main one (e.g. make them EA aware)?

I thought about doing that for the test cases we've written. Decimal('NaN') is the problem I've hit since we don't compare NaNs "correctly". But I don't think it'd be worthwhile putting in fixes for those specific ones since,

1.) It's only solving the problem for our specific functions. 3rd party libraries writing EAs would have no way to fix it.
2.) It's complicating our assert_*_equal methods for very little gain.

> (otherwise easy to accidently NOT use self.assert_*

Yes, this is going to be a problem going forward. I'm not sure how best to avoid it, but avoiding a `tm` import is a good start.
I could also add a linting rule that looks for `tm.assert*` in these submodules. Thoughts?

Edit: ahh that may be hard since in a followup I define `assert_*_equal` for DecimalArray, but it uses `tm.assert_*_` internally.
> why are we advertising this kind of api for testing? when we always use tm.assert_*? this is too easy to get wrong. wouldn't it be better to use that as the main one (e.g. make them EA aware)?

It's only for testing extension arrays (so for developers), not public API for users. 
The problem is that we cannot know in general how an extension array will be laid out internally, so we cannot make our test methods fully aware of them.

Although, one alternative would be to define a `equals` method on ExtensionArray that deals with NaNs.
> Although, one alternative would be to define a equals method on ExtensionArray that deals with NaNs.

And then just call `.equals` on it in `assert_series_equal` if they're an extension dtype? I could get behind that.
I am only not sure I am fully convinced myself :). The problem with and `.equals` method like that, it that it does not leave the space for an element-wise equals method. But of course with `Series.equals` already there, it might also be confusing that add such a method as an extension author. 
> does not leave the space for an element-wise equals method

I think following the lead of `Categorical` is best here. `.equals` for returning True/False and `.__eq__` for elementwise.

That said, `.equals` isn't great for the `assert_*_equal` methods since we want an informative traceback.

I should be able to add a linting rule that looks for `tm.assert_*_equal` only the the `extension/base` module. Then we're free to use it in `extension/decimal.py`
# [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/19863?src=pr&el=h1) Report
> :exclamation: No coverage uploaded for pull request base (`master@01e99de`). [Click here to learn what that means](https://docs.codecov.io/docs/error-reference#section-missing-base-commit).
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://codecov.io/gh/pandas-dev/pandas/pull/19863/graphs/tree.svg?token=eZ4WkYLtcO&src=pr&height=150&width=650)](https://codecov.io/gh/pandas-dev/pandas/pull/19863?src=pr&el=tree)

```diff
@@            Coverage Diff            @@
##             master   #19863   +/-   ##
=========================================
  Coverage          ?   91.64%           
=========================================
  Files             ?      150           
  Lines             ?    48946           
  Branches          ?        0           
=========================================
  Hits              ?    44858           
  Misses            ?     4088           
  Partials          ?        0
```

| Flag | Coverage Δ | |
|---|---|---|
| #multiple | `90.02% <ø> (?)` | |
| #single | `41.81% <ø> (?)` | |


------

[Continue to review full report at Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/19863?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/19863?src=pr&el=footer). Last update [01e99de...e0164a4](https://codecov.io/gh/pandas-dev/pandas/pull/19863?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

OK, this should now fail if tests in `extension/base/*.py` use `tm.assert_(frame|series)_equal`. I've excluded `base/base.py` since that's where the defaults are set.
> I think following the lead of Categorical is best here. .equals for returning True/False and .__eq__ for elementwise.

But, `__eq__` has no flexibilty regarding NaNs, so that's a reason one would want a element-wise `equals` (and from that, you can always do a `.all()` to get a single boolean). Anyhow, the existing behaviour is of course there, but if I would design it from scratch, not sure if I would do `equals` as it is now.
But for this PR, I would personally for now do like you did here. We can later still discuss if we want an `equals` method or not.
thanks!