Metadata-Version: 2.1
Name: streamlit_mock
Version: 0.0.1
Summary: Mocks the stremlit interfaces for unit testing
Project-URL: repository, https://github.com/acschofield/streamlit_mock
Author-email: Andrew Schofield <andrew@schofield.ch>
License: MIT License
        
        Copyright (c) 2022 Andrew Schofield
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Requires-Python: >=3.8
Requires-Dist: addict
Description-Content-Type: text/markdown

# streamlit_mock

Mock of streamlit to allow unit tests

## Background

Our simple streamlit applciation calling a REST API backend grew over time, became not so simple and needed a test suite.
We wrote some Selenium tests, but these are tricky to get right and run relatively slowly.
This package "mocks" most streamlit class to allow "pytest" to be used for testing.

Goals:

* Allow tests to be written using pytest
  
* Tests should run quickly so that multiple edge cases and variants can be tested
  
* Tests should be concise and easy to write

Non-Goals

* Testing streamlit itself (the package removes all dependnecies on the real streamlitk)
  
* Testing that the app uses Streamlit correctly (the package fakes input and records outputs)
  
* To be as complete as an end-to-end Selenium test (Streamlit/web server are out of the loop)

## Limitations

* The "mock" is probably missing some Streamlit calls.

* The "mock" code could probably be simplified using Python magic to remove some of the boilerplate

* If you want to mock the values of input elements, they should all have a "key" value. This may require some application changes but it is not obtrusive and is probably good preactice anyway.

## Usage

The "test" directory contains some very simple Streamlit applications, each with a corresponding test. The tests also
serve as programming examples.

```
$ cd test/simple_calculator
```

then, to run the application under streamlit:

```
$ streamlit run main_simple_calculator.py
```

and to run the test with Streamlit mocked out

```
$ pytest test_simple_calculator.py
```



## Writing tests

See the examples, but the steps are-.

1. import streamlit_mock - this adds itself to the front of the Python "path" so that the real Streamlit will not be used.

2. Create a "test_xxx" function to be executed by "pytest"

3. Set the inputs in `st.session_state`, See the "form_calculator" example to see how form_submit_button's are handled. These do not have a "key".
   
4. Run the streamlit application and get the "results".

5. "results" is a dictionary of lists where the interactions are recorded

6. Assert that the results are as expected. I have found it useful to temporarily print the results during test development to see what is expected/missing and then add asserts to confirm this behavior on future runs. Perhaps this should be added as a pytest option
   
## Tests requiring multiple "run"s

Some tests require that the streamlit application be run more than once to create intermediate results in `session_state`.

In this case, you can follow the following sps (assuminh two "run"s)

1. Create a StreamlitMock and get it's session_state in variable `session_state_1`
2. Set up the input values in `session_state_1`
3. Call "run" on the StreamlitMock object
4. Optionally assert some values in "results"
5. Create a new StreamlitMock and get its session_state in variable `session_state_2`
6. `session_state_2.update(session_state_1)`
7. Set additional input values in `session_state_2` for the second run
8. Call "run" on the second StreamlitMock object
9. Assert the results