I recently worked on a tool to wrap the creation of Autodesk Maya Constraints. I wanted to be able to validate the functionality of the tool without testing the GUI. Visual Studio (currently VS2013) is my IDE of choice and I really like the Test Explorer that is provided in VS for running and debugging tests. I find that running unit tests through VS is generally the quickest method to validate code functionality. Being able to develop and execute the code in the same environment leads to a seamless and productive experience in my opinion. Previously when I was using NUnit I had to run the NUnit GUI alongside VS. That experience felt a bit clunky when it came to debugging test failures. However, now there are VS extensions for most of the major testing frameworks (e.g. NUnit, xUnit, Google Test etc.) that support running their tests through the Test Explorer. More importantly VS can be extended to enable Python testing via the free open source plug-in called Python Tools for Visual Studio (PTVS). This plug-in enabled me to develop, debug and test Python code in VS2013.
Installation
- Install the PTVS plug-in from Codeplex
- Create a new environment and point it at the relevant Maya Python interpreter (This allows you to use PyMEL). Navigate to Tools – Options – Python Tools – Environment Options – Add Environment. I marked it as my default environment for convenience
Setup
Once installed Python project templates will be available to you when creating a new project. For the code associated with this post I created a basic Python Application project.
In order to add a new test file you can choose the Python Unit Test template which gives you the following shell class to start with. PTVS uses the standard Python testing framework – unittest. It is based on JUnit – the Java testing framework.
1 2 3 4 5 6 7 8 |
import unittest class SimplePythonTest(unittest.TestCase): def test_A(self): self.fail("Not implemented") if __name__ == '__main__': unittest.main() |
In order to create a test fixture, you can derive a class from unittest.TestCase as above. Define a setUp() and a tearDown() method for any preparation and clean-up actions that bookend the execution of each test. Prefix each test method with ‘test’ so that the unittest.TestLoader class, used by PTVS for test discovery, can automatically discover all of the tests. When the TestLoader class is invoked on a module, it searches for all classes that derive from TestCase. For each class that it finds, a new instance of that class is created for each test method defined in the class. Finally the unittest.main() call above allows you to run the script directly in order to execute the tests instead of running them through the Test Explorer in VS.
PyMEL and PTVS
PyMEL is built on top of the existing Python translation of MEL, in Maya’s Command module. The Maya Command module contains a direct translation of MEL into Python, whereas PyMEL adheres to the Pythonic philosophy. Here are instructions on how to get PyMEL working with PTVS. They refer to VS2012, but they still apply for VS2013.
I mentioned above that there were multiple methods of running Python tests. You can run them through the Test Explorer in VS or through a script by invoking unittest.main(). They can also be run inside Maya. Running inside Maya is the easiest option as the environment is already loaded. However, if you wish to run the tests from the command line or through the Test Explorer, then the Maya environment needs to be loaded. This can be achieved through loading the Maya standalone module. There is a catch though. Loading the Maya standalone module will throw an exception from within Maya. You can ignore that exception so that you execute the same code from within Maya and via the Test Explorer.
1 2 3 4 5 6 7 8 9 10 |
# load the maya libraries that allow a python script to run a windowless # version of maya this will allow our unit tests to run from a command line import maya.standalone as ms # attempt to intiliaze the standalone libraries, if this script is # being run insde of maya then maya will throw an exception try: ms.initialize(name='python') except: pass |
When running the tests via the Test Explorer each test loads the Maya standalone module in order to run Maya in windowless mode. This incurs a cost which makes running the tests slower in VS compared to running them in Maya. The images below show that running the PyMEL tests from the sample code took around two seconds through VS whereas they took around a hundredth of a second in Maya.
[cryout-multi][cryout-column width=”1/2″]
[/cryout-column]
[cryout-column width=”1/2″]
[/cryout-column] [/cryout-multi]
While there is a time discrepancy it isn’t substantial enough to make PTVS unusable. Being able to debug the tests individually is invaluable, which I feel makes PTVS a very useful plug-in for Python/PyMEL development. I have concentrated on the testing and debugging facets but there are other great features such as the static analysis tool PyLint, and the general editing experience through Intellisense. Don’t just take my word for it, take a look for yourself 🙂
Source Code
The source for the PyMEL project can be found on Bitbucket
References
Microsoft’s best-kept secret by Scott Hanselman