text: Title: Allow using tb['some_object'] or tb.get('some_object') instead of tb.ref('some_object')
  Body: It's more Pythonic, easier to remember, and makes it easy to migrate in-notebook tests to a script.
  
  Here's my use case:
  When I'm working on a notebook, I like to write tests inline first, and then move it to a `test.py` file:
  
  ```python
  # notebook.ipynb
  
  def add(x, y):
    return x + y
   
  def test_add():
    assert add(2, 3) == 5
  ```
  
  This allows me to test the function instantly without having to leave Jupyter, open a terminal, create a new script, etc., etc. This is especially useful when I'm using Binder, Colab, or Kaggle notebooks, and opening up a terminal or a new script isn't that straightforward.
  
  Later, I move the test to a `test.py` file:
  
  ```python
  # test.py
  
  def test_add(tb):
    add = tb.ref('add')
    assert add(2, 3)
  ```
  
  This requires an additional step of adding the `tb` argument and accessing `add` using `tb.ref('add')`. This change has to be made for every single test I write and every time I update a test in my notebook.
  
  It'd be nice is if I could use `tb` like a dictionary. Then, I can write the tests within my notebook in this fashion:
  
  ```python
  # notebook.ipynb
  
  def add(x, y):
    return x + y
  
  def test_add(tb):
    add = tb['add'] # or tb.get('add') for safety
    assert add(2, 3) == 5
  
  # A simple in-notebook test runner
  def run_test(test):
    return test(globals())
  
  ```
  
  Within the notebook I can run the tests by simply passing `globals()` as the value for `tb` and then I can easily migrate the tests to a script without making any code changes. 
  
  ```python
  # test.py
  
  def test_add(tb):
    add = tb['add'] # or tb.get('add') for safety
    assert add(2, 3) == 5
  
  # Look ma, no changes!
  ```
  
  