mozilla
Your Search Results

    xpcshellベースのユニットテスト(単体テスト)の書き方

    xpcshellツールはいくつかの種類の機能のテストに利用可能です。XPCOMの層で(スクリプトから利用可能なインターフェースを通じて)利用可能な物は、xpcshellでテストする事ができます。より多くの情報への手がかりを得るにはMozillaの自動テストおよび "automated testing" タグが指定されているページを参照してください。

    初めてのxpcshellベースのテスト

    初めてのxpcshellベースのテストの作り方は、簡単です。以下の内容で、test_first.js という名前(ユニットテストのファイル名は必ず test_ で始めてください)のファイルを作成してください。:

    function run_test()
    {
      // 何か複雑な処理を行い、その結果としてどのような結果が望まれているのかをここに書いてください。
      // これはただの例なので、trueを返しています。
      do_check_true(true);
    }
    

    これは実際には何もテストしませんが、実際にどのようにテストを書けばよいのかについての考え方を示しています。テストを実行したい時には、--disable-tests オプション無しでビルドした、スタティックでないブラウザを使う必要があります。テストファイルを既存のテストのセットの中に追加してください(例えばnetwork/test/unit/など。ただし、レビューのために投稿されるテストの場合は、別の位置に置く事になるでしょう)。そうすると、あなたが書いたテストを make xpcshell-tests で実行できるようになります。:

    $ cd objdir
    $ make -C netwerk/test/ xpcshell-tests
    ...失敗または成功の旨のメッセージがコンソールに出力されます...
    
    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
    

    デバッガにアタッチしたり、その他の細かい制御をしたければ、"check-one" を "check-interactive"に変更してください。そうすれば、テストを対話的に実行することもできます。

    自分のテストを追加する

    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_execute_soon(callback)
    Executes the function callback on a later pass through the event loop. Use this when you want some code to execute after the current function has finished executing, but you don't care about a specific time delay. This function will automatically insert a do_test_pending / do_test_finished pair for you.

     

    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 netwerk/test/Makefile.in#117.
    do_get_profile()
    Registers a directory with the profile service and returns an nsILocalFile object representing that directory. It also makes sure that the profile-change-net-teardown, profile-change-teardown and profile-before-change observer notifications are sent before the test finishes. This is useful if the components loaded in the test observe them to do clean-up on shutdown (e.g. places).
    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_get_idle()
    By default XPCShell tests will disable the idle service, so that idle time will always be reported as 0.  Calling this function will re-enable the service and return a handle to it, the idle time will be then correctly requested to the underlying OS.  The idle-daily notification could be fired when requesting idle service. It is suggested to always get the service through this method if the test has to use idle.
    do_register_cleanup(callback)
    Executes the function callback after the test has finished running, regardless of whether the test passes or fails. You can use this to clean up anything that might otherwise cause problems between test runs.

     

    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 <code>toolkit/components/commandlines/test/Makefile.in</code>.

    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 バグ 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 バグ 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
    

    Debugging Electrolysis (e10s) xpcshell tests

    Under e10s you have two processes.  You can debug the chrome process, the child process, or both at the same time. 

    To debug the chrome process

    simply use "make check-interactive" as described above.  

    To debug the child process

    The child process is where your xpcshell test's JS code is being run, so it is often--but not always--the process you're interested in.  To debug the child, set MOZ_DEBUG_CHILD_PROCESS=1 in your environment (or on the command line) and run "make check-one", and you will see the child process emit a printf with its process ID, then sleep.  Attach a debugger to the child's pid, and when it wakes up you can debug it:  

    $MOZ_DEBUG_CHILD_PROCESS=1 SOLO_FILE=test_simple_wrap.js make check-one
    CHILDCHILDCHILDCHILD
      debug me @13476
    
    

    To debug both parent and child processes

    Use MOZ_DEBUG_CHILD_PROCESS=1 with "make check-interactive", and attach debuggers to each process. (For gdb at least, this means running separate copies of gdb, one for each process.)

    ドキュメントのタグと貢献者

    Contributors to this page: Potappo, Piro, Kozawa
    最終更新者: Potappo,