Testing Tutorial Step 2. Create your machine folder
===================================================

`Step 2 of the MPF Tutorial <https://missionpinball.org/tutorial/2_creating_a_new_machine>`_ is where
you create your machine folder and get MPF up and running with an empty config. Since it ends with MPF running and the
attract mode being active, we can actually write a test for it!

Here are the steps to take:

1. Create a "tests" folder in your machine folder
-------------------------------------------------

First, create a folder called ``tests`` in your machine folder. This would be alongside the other folders
in there, which will be "config" (created in the MPF tutorial), as well as "logs" and "data" which were
created automatically by MPF the first time it ran.

2. Add an empty "__init__.py" file
----------------------------------

Next, inside your new *tests* folder, create a blank file called ``__init__.py``. (That's two underscores,
then the word "init", then two more underscores, then ".py".) This file should be totally blank. (It just needs
to exist.) This file is needed to let the Python test runner find and load the tests from this folder.

3. Add a test file
------------------

Next you need to add a Python file which actually holds your tests. You can name this file whatever you want
as long as it starts with "test". (The reason for starting it with "test" is also so that the Python test runner
knows that this file contains tests, allowing it to automatically find and run tests from it.)

For now let's call it ``test_step_2.py``.

Open that file and add the following lines to it: (If you are interested in what all this means, then read on
below the file. Otherwise you can skip down to Step 4.)

.. include:: ../../examples/tutorial/step_2/tests/test_step_2.py
   :code: python

So what's this file actually doing?

The import line just imports the base class we use for MPF machine tests. (More details on that is covered in
the :doc:`Testing Class API page </api/tests_overview>`).

Our specific class name ``TestTutorialMachine`` can be whatever you want. Again just make sure it starts with "Test" in
order for the test runner to find out.

Our specific method is called ``test_step_2_mpf_startup()``. (Also it has to start with "test"). When the tests are run
each method represents a separate "run" of MPF. The test runner will start up MPF and get it all up and running, and then
it will move through the code in the test method, then it will cleanly shut down MPF when it's done. If there are
multiple test methods, then the test running will start and stop MPF multiple times. The key is that each test method
is run against a "fresh" MPF copy.

These test methods will also load the machine config files (just like if the command ``mpf`` was run the regular way).

Anyway, in our test method, we have the only actual line that does anything:

.. code-block:: python

   self.assertModeRunning('attract')

This just tests ("asserts") that a mode called "attract" is running. There are all sorts of MPF-specific assertion
methods which we'll cover in later steps of this tutorial.

4. Run your test
----------------

You can run your tests via the command prompt from your machine folder. (In other words, the same place where you run
``mpf`` to run your machine.)

The exact command to run is ``python -m unittest``. This should produce output similar to the following:

.. code-block:: doscon

   C:\pinball\your_machine>python -m unittest
   C:\Python34\lib\imp.py:32: PendingDeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses
     PendingDeprecationWarning)
   .
   ----------------------------------------------------------------------
   Ran 1 test in 0.734s

   OK

   C:\pinball\your_machine>

That warning about the deprecation can be ignored (if you even have it.. you might not). The important thing is the
message towards the bottom: "Ran 1 test in 0.734s" and the "OK" below it. That means your test passed!

5. Check out a failed test
--------------------------

When you're writing unit tests, you'll end up dealing with failed tests a lot! So let's purposefully change the
test so it fails. In this case, change the line which asserts a mode called "attract" is running to look for a mode
called "foo" instead, like this:

.. code-block:: python

   self.assertModeRunning('foo')

Save the file and rerun the tests and you should see results like this:

.. code-block:: doscon

   C:\pinball\your_machine>python -m unittest
   C:\Python34\lib\imp.py:32: PendingDeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses
     PendingDeprecationWarning)
   F
   ======================================================================
   FAIL: test_mpf_starts (tests.test_step_2.TestTutorialMachine)
   Tests Step 2 of the tutorial
   ----------------------------------------------------------------------
   Traceback (most recent call last):
     File "C:\pinball\your_machine\tests\test_step_2.py", line 18, in test_mpf_starts
       self.assertModeRunning('foo')
     File "C:\Python34\lib\site-packages\mpf\tests\MpfTestCase.py", line 576, in assertModeRunning
       raise AssertionError("Mode {} not known.".format(mode_name))
   AssertionError: Mode foo not known.

   ----------------------------------------------------------------------
   Ran 1 test in 0.594s

   FAILED (failures=1)

   C:\pinball\your_machine>

Note that we see the test run failed, with one failure, and that we can scroll up and see the specific name of the test
that failed along with the line that failed, and information about the failure. (In this case it tells us that the mode
"foo" is not known.)

So to get this test to work, you either need to change your MPF config to start a mode called "foo", or you need to
change the test back to looking for a mode called "attract". :)


What if it didn't work?
-----------------------

If the unit tests don't work for you, there are a few things you can try.

If you get some kind of loading error or config error, make sure you're running ``python -m unittest`` from your
machine folder (not from the "tests" folder).

If you get a message about 0 tests run, make sure you have that empty ``__init__.py`` in your tests folder.

And if you get some weird error that you can't figure out, then post a message to the `MPF Google Group <https://groups.google.com/forum/#!forum/mpf-users>`_.
