mozilla

Revision 21615 of Writing xpcshell-based unit tests

  • Revision slug: Writing_xpcshell-based_unit_tests
  • Revision title: Writing xpcshell-based unit tests
  • Revision id: 21615
  • Created:
  • Creator: azakai
  • Is current revision? No
  • Comment no changes

Revision Content

 

The xpcshell tool can be used to test certain kinds of functionality. Anything available to the XPCOM layer (through scriptable interfaces) can be tested with xpcshell. See Mozilla automated testing and pages tagged "automated testing" for pointers to more information.

Your first xpcshell-based test

Creating your first xpcshell-based test is easy. Create a file named test_first.js (unit test filenames must start with test_) with the following:

function run_test() {
  // do some complex action, check whether the action's results were what are expected here
  // this is just an example, so we assert that true == true
  do_check_true(true);
}

This doesn't really test anything, but it gives you an idea how you'd actually write a test. If you want to execute the test, you must create a non-static build of the browser without --disable-tests. Add the test file to an existing set of tests (say, for example, {{ Source("netwerk/test/unit/") }}, but you'll want a different location when your test is posted for a review). You then execute your test using make xpcshell-tests:

$ cd objdir
$ make -C netwerk/test/ xpcshell-tests
...failure or success messages are printed to the console...
Note:

You can now specify check-one instead of xpcshell-tests on the command line to launch a single test

$ cd objdir
$ make SOLO_FILE="test_resumable_channel.js" -C netwerk/test/ check-one

You can also run your tests interactively, if you would like to attach a debugger or exert more control over the test run, by replacing "check-one" with "check-interactive".

Adding to your test

The test is executed by the test harness by calling the run_test function defined in the file. Anything you want to test must be spawned from this function.

If you have a group of files in a directory and they all include some common code that needs to run before your tests, to set up resources for example, you can put one copy of that code in a source file whose name starts with head_ and ends with .js. Any code that is common to your test and which needs to run after your tests can be put into a source file that starts with tail_ and ends with .js. You should also name your test source files with names that start with test_ and end with .js. Each of your test files needs to contain at least a "run_test()" function. If the "run_test()" function runs to completion without throwing an exception, the test succeeds. (If you need to do any asynchronous tests, see do_test_pending and do_test_finished below.)

If you want to import a common module in your tests you can use resource://test to load it. This special address always resolves to the current test folder.

Components.utils.import("resource://test/module.jsm"); // Import module.jsm that is in the same folder as current test.

xpcshell tests have access to the following utility functions:

do_throw(messageText)
Call this function to report an error and exit the test. The argument is a string that will be reported in the test's log file.
Note: While do_throw can be caught by a try/catch block, executing it will cause the test to fail when it completes.
do_check_eq(a, b)
Call this function to assert that two objects are equal. If not equal, an exception is logged and the test case is halted.
do_check_neq(a, b)
Call this function to assert that two objects are not equal. If equal, an exception is logged and the test case is halted.
do_check_true(expr)
Call this function to assert that expr is equal to true.
do_check_false(expr)
Call this function to assert that expr is equal to false.
do_get_file(testdirRelativePath, allowNonexistent)
Returns an nsILocalFile object representing the given file (or directory) in the test directory. For example, if your test is unit/test_something.js, and you need to access unit/data/somefile, you would call do_get_file('data/somefile'). The given path must be delimited with forward slashes. You can use this to access test-specific auxiliary files if your test requires access to external files. Note that you can also use this function to get directories.
Note: If your test needs access to one or more files that aren't in the test directory, you should install those files to the test directory in the Makefile where you specify XPCSHELL_TESTS. For an example, see {{ Source("netwerk/test/Makefile.in#117") }}.
do_get_cwd()
Returns an nsILocalFile object representing the test directory. This is the directory containing the test file when it is currently being run. Your test can write to this directory as well as read any files located alongside your test. Your test should be careful to ensure that it will not fail if a file it intends to write already exists, however.
load(testdirRelativePath)
Imports the JavaScript file referenced by testdirRelativePath into the global script context, executing the code inside it. The file specified is a file within the test directory. For example, if your test is unit/test_something.js and you have another file unit/extra_helpers.js, you can load the second file from the first simply by calling load('extra_helper.js').
do_load_httpd_js()
Imports the JavaScript test httpd server script into the global script context.
do_load_module(testdirRelativePath)
Calls do_get_file(testdirRelativePath), then registers the returned file.
do_parse_document(path, type)
Parses and returns a DOM document.
do_timeout(delay, fun)
Call this function to schedule a timeout. The given function will be called with no arguments provided after the specified delay (in milliseconds). Note that you must call do_test_pending so that the test isn't completed before your timer fires, and you must call do_test_finished when the actions you perform in the timeout complete, if you have no other functionality to test.  (Note: the function argument used to be a string argument to be passed to eval, and some older branches support only a string argument or support both string and function.)
do_test_pending()
Delay exit of the test until do_test_finished() is called. do_test_pending() may be called multiple times, and do_test_finished() must be paired with each before the unit test will exit.
do_test_finished()
Call this function to inform the test framework that an asynchronous operation has completed. If all asynchronous operations have completed (i.e. every do_test_pending() has been matched with a do_test_finished() in execution), then the unit test will exit.

Platform-specific tests

Sometimes you might want a test to know what platform it's running on (to test platform-specific features, or allow different behaviors). Unit tests are not normally invoked from a Makefile (unlike Mochitests), or preprocessed (so not #ifdefs), so platform detection with those methods isn't trivial.

Runtime detection

Some tests will want to only execute certain portions on specific platforms. One approach that's been used is to look for the existence of platform-specific components or interfaces. It's a bit hackish, but it's simple and it works.

  • For Windows:

var isWindows = ("@mozilla.org/windows-registry-key;1" in Components.classes);

  • For OS X:

var isOSX = ("nsILocalFileMac" in Components.interfaces);

  • For Linux:

var isLinux = ("@mozilla.org/gnome-gconf-service;1" in Components.classes);

Using Makefiles

If you have lots of platform-specific tests or don't want to mix various platform tests within the same directory, you can use some Makefile magic to add platform-specific directories (to XPCSHELL_TESTS) under your main unit test directory. For an example, see {{ Source("toolkit/components/commandlines/test/Makefile.in") }}.

Testing under Electrolysis

Since not all platforms support multi-process (electrolysis, aka "e10s"), you need to put any e10s-specific tests in a separate directory, and only run them if MOZ_IPC is defined.  See /netwerk/test/Makefile.in for an example.   Note that any "head_" or "tail_" scripts you have in your usual tests directory will not be run automatically in the new directory (but you can write a simple wrapper to load them: see "head_channels_clone.js" in netwerk/test/unit_ipc).

By default xpcshell tests run in the parent process.  If you wish to run test logic in the child, you have several ways to do it:

  1. Create a regular test_foo.js test, and then write a wrapper test_foo_wrap.js file that uses the run_test_in_child() function to run an entire script file in the child.   This is an easy way to arrange for a test to be run twice, once in chrome and then later (via the _wrap.js file) in content.  See /network/test/unit_ipc for examples.  The run_test_in_child() function takes a callback, so you should be able to call it multiple times with different files, if that's useful.
  2. For tests that need to run logic in both the parent + child processes during a single test run, you may use the poorly documented SendCommand() function, which takes a code string to be executed on the child, and a callback function to be run on the parent when it has completed.  You will want to first call do_load_child_test_harness() to set up a reasonable test environment on the child.  SendCommand returns immediately, so you will generally want to use do_test_pending/do_test_finished with it.    NOTE:  this method of test has not been used much, and your level of pain may be significant.  Consider option #1 if possible.

See the documentation for  run_test_in_child() and do_load_child_test_harness() in testing/xpcshell/head.js for more information.

Adding your tests to the list of mozilla tests

You should store your tests near the source of code you want to test. For example, imagine you want to add tests for your component in extensions/myextension/mycomponent, you will add a tests/ directory. You can store different kind of tests here (reftests etc.), and for xpcshell, you should create a unit directory and store all your javascript files inside it. Example: extensions/myextension/mycomponent/tests/unit/test_foo.js. The unit name is just convention, but if you only have one directory it's what is currently widely used.

Then you should create a extensions/myextension/mycomponent/tests/Makefile.in which will contain XPCSHELL_TESTS = unit. Of course, in the extensions/myextension/mycomponent/Makefile.in you will add tests/ into the DIRS variable.

Usage of the term 'extensions' in this section does not refer to Add-ons (i.e. extensions built to XPI). xpcshell is not aware of Add-ons (see {{ Bug("371329") }}), and in particular there is no support for Add-ons component interfaces to be loaded.

An Add-on without additional component interfaces can be tested by copying component files to the staging area, and then registering the components during the test using nsIComponentRegistrar. See CrashReporter unit tests for example of registration of components during tests using nsIComponentRegistrar (registration of all components in the components subfolder of the current working directory), and CrashReporter Makefile.in to see libs:: used for creating a folder for component files in the staging area, then copying them (C++ component in this example - for JS see example below).

# Additions to Makefile.in to copy to test staging area
_JS_COMPONENTS = \
	../src/mycomponent.js \
	../src/myothercomponent.js \
	$(NULL)   

libs::
	$(NSINSTALL) -D $(DEPTH)/_tests/xpcshell/$(MODULE)/unit/components

libs::	$(_JS_COMPONENTS)
	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/xpcshell/$(MODULE)/unit/components

A hack to test Add-ons with additional interfaces is to copy the generated XPT files to the OBJDIR/dist/bin/components/ folder, then delete (or rename) compreg.dat and xpti.dat (to force registration) before running running the tests (for information on running tests, see next section). Be careful not to overwrite existing XPTs. 

Running unit tests

Tests should be run using make -C OBJDIR/path_to_tests/ (to copy tests) and then make -C OBJDIR/path_to_tests/ xpcshell-tests (to run tests). Just cd to an appropriate directory (e.g. to run tests for a single module, go to MOZ_OBJDIR/path_to_tests/test/) and run make xpcshell-tests.

To run a single test, use the check-one target, as described above.

Note: You must run make -C OBJDIR/path_to_tests/ before trying to run tests; the tests are copied to a central location to be executed, and this copying occurs in the libs target of the build, which make xpcshell-tests does not invoke. On platforms with symlinks, you can edit and re-run the test without re-making the libs target, since the symlink will point to the file in your source directory.

Running unit tests under a C++ debugger

Via check-interactive

You can specify check-interactive when issuing the make command. This will cause your test to stop right before running so you can attach to xpcshell in a debugger (implemented in {{ Bug("382682") }}).

Example:

$ cd objdir
$ make SOLO_FILE="test_resumable_channel.js" -C netwerk/test/ check-interactive
# js>_execute_test();
...failure or success messages are printed to the console...
# js>quit();

Note: For comm-central builds (only?), the path passed to -C, giving the relative path from the base source directory to the test directory, must not contain the final /unit/ subdirectory, even if the actual SOLO_FILE is stored there!

$ ls -la uriloader/exthandler/tests/unit/test_punycodeURIs.js
$ make SOLO_FILE="test_punycodeURIs.js" -C uriloader/exthandler/tests/ check-interactive

{{ languages( { "ja": "ja/Writing_xpcshell-based_unit_tests" } ) }}

Revision Source

<p> </p>
<p>The <a href="/en/XPConnect/xpcshell" title="en/xpcshell">xpcshell</a> tool can be used to test certain kinds of functionality. Anything available to the XPCOM layer (through scriptable interfaces) can be tested with xpcshell. See <a href="/en/Mozilla_automated_testing" title="en/Mozilla_automated_testing">Mozilla automated testing</a> and <a class="internal" href="/Special:Tags?tag=Automated+testing" title="Special:Tags?tag=Automated+testing">pages tagged "automated testing"</a> for pointers to more information.</p>
<h3 name="Your_first_xpcshell-based_test">Your first xpcshell-based test</h3>
<p>Creating your first xpcshell-based test is easy. Create a file named <code>test_first.js</code> (unit test filenames must start with <code>test_</code>) with the following:</p>
<pre class="eval">function run_test() {
  // do some complex action, check whether the action's results were what are expected here
  // this is just an example, so we assert that true == true
  do_check_true(true);
}
</pre>
<p>This doesn't really test anything, but it gives you an idea how you'd actually write a test. If you want to execute the test, you must create a non-static build of the browser without <code>--disable-tests</code>. Add the test file to an existing set of tests (say, for example, {{ Source("netwerk/test/unit/") }}, but you'll want a different location when your test is posted for a review). You then execute your test using <code>make xpcshell-tests</code>:</p>
<pre class="eval">$ cd <strong>objdir</strong>
$ make -C netwerk/test/ xpcshell-tests
...failure or success messages are printed to the console...
</pre>
<div class="note"><strong>Note:</strong>
<p>You can now specify <code>check-one</code> instead of xpcshell-tests on the command line to launch a single test</p>
<pre class="eval">$ cd <strong>objdir</strong>
$ make SOLO_FILE="test_resumable_channel.js" -C netwerk/test/ check-one
</pre>
<p>You can also run your tests interactively, if you would like to attach a debugger or exert more control over the test run, by replacing "check-one" with "check-interactive".</p>
</div>
<h3 name="Adding_to_your_test">Adding to your test</h3>
<p>The test is executed by the test harness by calling the <code>run_test</code> function defined in the file. Anything you want to test must be spawned from this function.</p>
<p>If you have a group of files in a directory and they all include some common code that needs to run before your tests, to set up resources for example, you can put one copy of that code in a source file whose name starts with <code>head_</code> and ends with <code>.js</code>. Any code that is common to your test and which needs to run after your tests can be put into a source file that starts with <code>tail_</code> and ends with <code>.js</code>. You should also name your test source files with names that start with <code>test_</code> and end with <code>.js</code>. Each of your test files needs to contain at least a "<code>run_test()</code>" function. If the "<code>run_test()</code>" function runs to completion without throwing an exception, the test succeeds. (If you need to do any asynchronous tests, see <code>do_test_pending</code> and <code>do_test_finished</code> below.)</p>
<p>If you want to import a common module in your tests you can use <code><a class=" external" href="resource://test" rel="freelink">resource://test</a></code> to load it. This special address always resolves to the current test folder.</p>
<pre><span style="color: rgb(0, 136, 0);">Components.utils.import("resource://test/module.jsm"); // Import module.jsm that is in the same folder as current test.<br></span></pre>
<p>xpcshell tests have access to the following utility functions:</p>
<dl> <dt><code>do_throw(<em>messageText</em>)</code></dt> <dd>Call this function to report an error and exit the test. The argument is a string that will be reported in the test's log file.</dd> <dd><em>Note</em>: While <code>do_throw</code> can be caught by a <code>try/catch</code> block, executing it will cause the test to fail when it completes.</dd>
</dl>
<dl> <dt><code>do_check_eq(<em>a</em>, <em>b</em>)</code></dt> <dd>Call this function to assert that two objects are equal. If not equal, an exception is logged and the test case is halted.</dd>
</dl>
<dl> <dt><code>do_check_neq(<em>a</em>, <em>b</em>)</code></dt> <dd>Call this function to assert that two objects are not equal. If equal, an exception is logged and the test case is halted.</dd>
</dl>
<dl> <dt><code>do_check_true(<em>expr</em>)</code></dt> <dd>Call this function to assert that <code>expr</code> is equal to <code>true</code>.</dd>
</dl>
<dl> <dt><code>do_check_false(<em>expr</em>)</code></dt> <dd>Call this function to assert that <code>expr</code> is equal to <code>false</code>.</dd>
</dl>
<dl> <dt><code>do_get_file(<em>testdirRelativePath, allowNonexistent</em>)</code></dt> <dd>Returns an <a href="/en/nsILocalFile" title="en/nsILocalFile">nsILocalFile</a> object representing the given file (or directory) in the test directory. For example, if your test is unit/test_something.js, and you need to access unit/data/somefile, you would call <code>do_get_file('data/somefile')</code>. The given path must be delimited with forward slashes. You can use this to access test-specific auxiliary files if your test requires access to external files. Note that you can also use this function to get directories. <div class="note"><strong>Note:</strong> If your test needs access to one or more files that aren't in the test directory, you should install those files to the test directory in the Makefile where you specify <code>XPCSHELL_TESTS</code>. For an example, see {{ Source("netwerk/test/Makefile.in#117") }}.</div> </dd>
</dl>
<dl> <dt><code>do_get_cwd()</code></dt> <dd>Returns an <a href="/en/nsILocalFile" title="en/nsILocalFile">nsILocalFile</a> object representing the test directory. This is the directory containing the test file when it is currently being run. Your test can write to this directory as well as read any files located alongside your test. Your test should be careful to ensure that it will not fail if a file it intends to write already exists, however.</dd>
</dl>
<dl> <dt><code>load(<span style="font-style: italic;">test</span><em>dirRelativePath</em>)</code></dt> <dd>Imports the JavaScript file referenced by <code><em>testdirRelativePath</em></code> into the global script context, executing the code inside it. The file specified is a file within the test directory. For example, if your test is unit/test_something.js and you have another file unit/extra_helpers.js, you can load the second file from the first simply by calling <code>load('extra_helper.js')</code>.</dd>
</dl>
<dl> <dt><code>do_load_httpd_js()</code></dt> <dd>Imports the <a class="internal" href="/En/Httpd.js/HTTP_server_for_unit_tests" title="en/HTTP server for unit tests">JavaScript test httpd server</a> script into the global script context.</dd>
</dl>
<dl> <dt><code>do_load_module(</code><code><em>testdirRelativePath</em></code><code>)</code></dt> <dd>Calls do_get_file(<code><em>testdirRelativePath</em></code>), then registers the returned file.</dd>
</dl>
<dl> <dt><code>do_parse_document(<span style="font-style: italic;">p</span></code><code><em>ath, type</em></code><code>)</code></dt> <dd>Parses and returns a DOM document.</dd>
</dl>
<dl> <dt><code>do_timeout(<em>delay</em>, <em>fun</em>)</code></dt> <dd>Call this function to schedule a timeout. The given function will be called with no arguments provided after the specified delay (in milliseconds). Note that you must call do_test_pending so that the test isn't completed before your timer fires, and you must call do_test_finished when the actions you perform in the timeout complete, if you have no other functionality to test.  (Note: the function argument used to be a string argument to be passed to eval, and some older branches support only a string argument or support both string and function.)</dd>
</dl>
<dl> <dt><code>do_test_pending()</code></dt> <dd>Delay exit of the test until do_test_finished() is called. do_test_pending() may be called multiple times, and do_test_finished() must be paired with each before the unit test will exit.</dd>
</dl>
<dl> <dt><code>do_test_finished()</code></dt> <dd>Call this function to inform the test framework that an asynchronous operation has completed. If all asynchronous operations have completed (i.e. every do_test_pending() has been matched with a do_test_finished() in execution), then the unit test will exit.</dd>
</dl>
<h3>Platform-specific tests</h3>
<p>Sometimes you might want a test to know what platform it's running on (to test platform-specific features, or allow different behaviors). Unit tests are not normally invoked from a Makefile (unlike Mochitests), or preprocessed (so not #ifdefs), so platform detection with those methods isn't trivial.</p>
<h4>Runtime detection</h4>
<p>Some tests will want to only execute certain portions on specific platforms. One approach that's been used is to look for the existence of platform-specific components or interfaces. It's a bit hackish, but it's simple and it works.</p>
<ul> <li>For Windows:</li>
</ul>
<p style="margin-left: 40px;"><code>var isWindows = ("@mozilla.org/windows-registry-key;1" in Components.classes);</code></p>
<ul> <li>For OS X:</li>
</ul>
<p style="margin-left: 40px;"><code>var isOSX = ("nsILocalFileMac" in Components.interfaces);</code></p>
<ul> <li>For Linux:</li>
</ul>
<p style="margin-left: 40px;"><code>var isLinux = ("@mozilla.org/gnome-gconf-service;1" in Components.classes);</code></p>
<h4>Using Makefiles</h4>
<p>If you have lots of platform-specific tests or don't want to mix various platform tests within the same directory, you can use some Makefile magic to add platform-specific directories (to XPCSHELL_TESTS) under your main unit test directory. For an example, see {{ Source("<code>toolkit/components/commandlines/test/Makefile.in</code>") }}.</p>
<h3>Testing under Electrolysis</h3>
<p>Since not all platforms support multi-process (electrolysis, aka "e10s"), you need to put any e10s-specific tests in a separate directory, and only run them if MOZ_IPC is defined.  See /netwerk/test/Makefile.in for an example.   Note that any "head_" or "tail_" scripts you have in your usual tests directory will not be run automatically in the new directory (but you can write a simple wrapper to load them: see "head_channels_clone.js" in netwerk/test/unit_ipc).</p>
<p>By default xpcshell tests run in the parent process.  If you wish to run test logic in the child, you have several ways to do it:</p>
<ol> <li>Create a regular test_foo.js test, and then write a wrapper test_foo_wrap.js file that uses the run_test_in_child() function to run an entire script file in the child.   This is an easy way to arrange for a test to be run twice, once in chrome and then later (via the _wrap.js file) in content.  See /network/test/unit_ipc for examples.  The run_test_in_child() function takes a callback, so you should be able to call it multiple times with different files, if that's useful.</li> <li>For tests that need to run logic in both the parent + child processes during a single test run, you may use the poorly documented SendCommand() function, which takes a code string to be executed on the child, and a callback function to be run on the parent when it has completed.  You will want to first call do_load_child_test_harness() to set up a reasonable test environment on the child.  SendCommand returns immediately, so you will generally want to use do_test_pending/do_test_finished with it.    NOTE:  this method of test has not been used much, and your level of pain may be significant.  Consider option #1 if possible.</li>
</ol>
<p>See the documentation for  run_test_in_child() and do_load_child_test_harness() in testing/xpcshell/head.js for more information.</p>
<h3>Adding your tests to the list of mozilla tests</h3>
<p>You should store your tests near the source of code you want to test. For example, imagine you want to add tests for your component in <code>extensions/myextension/mycomponent</code>, you will add a <code>tests/</code> directory. You can store different kind of tests here (reftests etc.), and for xpcshell, you should create a <code>unit</code> directory and store all your javascript files inside it. Example: <code>extensions/myextension/mycomponent/tests/unit/test_foo.js</code>. The <code>unit</code> name is just convention, but if you only have one directory it's what is currently widely used.</p>
<p>Then you should create a <code>extensions/myextension/mycomponent/tests/Makefile.in</code> which will contain <code>XPCSHELL_TESTS = unit</code>. Of course, in the <code>extensions/myextension/mycomponent/Makefile.in</code> you will add <code>tests/</code> into the <code>DIRS</code> variable.</p>
<div class="warning">Usage of the term 'extensions' in this section does not refer to Add-ons (i.e. extensions built to XPI). xpcshell is not aware of Add-ons (see {{ Bug("371329") }}), and in particular there is no support for Add-ons component interfaces to be loaded.</div>
<p>An Add-on without additional component interfaces can be tested by copying component files to the staging area, and then registering the components during the test using nsIComponentRegistrar. See <a class=" external" href="http://mxr.mozilla.org/mozilla-central/source/toolkit/crashreporter/test/unit/" title="http://mxr.mozilla.org/mozilla-central/source/toolkit/crashreporter/test/unit/">CrashReporter unit tests</a> for example of registration of components during tests using <a href="/en/XPCOM_Interface_Reference/nsIComponentRegistrar" title="en/XPCOM Interface Reference/nsIComponentRegistrar">nsIComponentRegistrar</a> (registration of all components in the components subfolder of the current working directory), and <a class=" external" href="http://mxr.mozilla.org/mozilla-central/source/toolkit/crashreporter/test/Makefile.in#89" title="http://mxr.mozilla.org/mozilla-central/source/toolkit/crashreporter/test/Makefile.in#89">CrashReporter Makefile.in</a> to see <code>libs::</code> used for creating a folder for component files in the staging area, then copying them (C++ component in this example - for JS see example below).</p>
<pre class="brush: shell"># Additions to Makefile.in to copy to test staging area
_JS_COMPONENTS = \
	../src/mycomponent.js \
	../src/myothercomponent.js \
	$(NULL)   

libs::
	$(NSINSTALL) -D $(DEPTH)/_tests/xpcshell/$(MODULE)/unit/components

libs::	$(_JS_COMPONENTS)
	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/xpcshell/$(MODULE)/unit/components
</pre>
<p>A hack to test Add-ons with additional interfaces is to copy the generated XPT files to the OBJDIR/dist/bin/components/ folder, then delete (or rename) compreg.dat and xpti.dat (to force registration) before running running the tests (for information on running tests, see next section). Be careful not to overwrite existing XPTs. </p>
<h3 name="Running_unit_tests">Running unit tests</h3>
<p>Tests should be run using <code>make -C <em>OBJDIR/path_to_tests/</em></code> (to copy tests) and then <code>make -C <em>OBJDIR/path_to_tests/</em></code><em><code> xpcshell-tests</code></em> (to run tests). Just <code>cd</code> to an appropriate directory (e.g. to run tests for a single module, go to <code><a href="/en/MOZ_OBJDIR" title="en/MOZ_OBJDIR">MOZ_OBJDIR</a>/<em>path_to_tests</em>/test/</code>) and run <code>make </code><em><code>xpcshell-tests</code></em>.</p>
<p>To run a single test, use the <code>check-one</code> target, as described above.</p>
<div class="note"><strong>Note:</strong> You must run <code>make -C <em>OBJDIR/path_to_tests/</em></code> before trying to run tests; the tests are copied to a central location to be executed, and this copying occurs in the <code>libs</code> target of the build, which <code>make <em><span style="font-family: Verdana,Tahoma,sans-serif;">xpcshell-tests</span></em></code> does not invoke. On platforms with symlinks, you can edit and re-run the test without re-making the libs target, since the symlink will point to the file in your source directory.</div>
<h3 name="Running_unit_tests_under_a_C.2B.2B_debugger">Running unit tests under a C++ debugger</h3>
<h4 name="Via_check-interactive">Via <code>check-interactive</code></h4>
<p>You can specify <code>check-interactive</code> when issuing the <code>make</code> command. This will cause your test to stop right before running so you can attach to xpcshell in a debugger (implemented in {{ Bug("382682") }}).</p>
<p>Example:</p>
<pre class="eval">$ cd <strong>objdir</strong>
$ make SOLO_FILE="test_resumable_channel.js" -C netwerk/test/ check-interactive
# js&gt;_execute_test();
...failure or success messages are printed to the console...
# js&gt;quit();
</pre>
<p><em>Note: For comm-central builds (only?), the path passed to -C, giving the relative path from the base <strong>source</strong> directory to the test directory, must not contain the final /unit/ subdirectory, even if the actual SOLO_FILE is stored there!</em></p>
<pre class="eval">$ ls -la uriloader/exthandler/tests/unit/test_punycodeURIs.js
$ make SOLO_FILE="test_punycodeURIs.js" -C uriloader/exthandler/tests/ check-interactive
</pre>
<p>{{ languages( { "ja": "ja/Writing_xpcshell-based_unit_tests" } ) }}</p>
Revert to this revision