diff --git a/payment/payment.info b/payment/payment.info
index 1643906..f25dcaf 100644
--- a/payment/payment.info
+++ b/payment/payment.info
@@ -15,4 +15,5 @@ files[] = views/PaymentViewsHandlerFieldPaymentOperations.inc
 files[] = views/PaymentViewsHandlerFieldTranslatableString.inc
 files[] = views/PaymentViewsHandlerFilterPaymentMethodControllerTitle.inc
 files[] = views/PaymentViewsHandlerFilterPaymentMethodTitle.inc
-files[] = views/PaymentViewsHandlerFilterPaymentStatusItemStatus.inc
\ No newline at end of file
+files[] = views/PaymentViewsHandlerFilterPaymentStatusItemStatus.inc
+files[] = tests/PaymentWebTestCase.test
\ No newline at end of file
diff --git a/payment/tests/PaymentWebTestCase.test b/payment/tests/PaymentWebTestCase.test
new file mode 100644
index 0000000..809b3c6
--- /dev/null
+++ b/payment/tests/PaymentWebTestCase.test
@@ -0,0 +1,72 @@
+<?php
+
+/**
+ * Contains class PaymentWebTestCase.
+ */
+
+/**
+ * Provides reusable code for testing payments and payment methods.
+ */
+class PaymentWebTestCase extends XtoolsWebTestCase {
+
+  /**
+   * Overrides parent::setUp().
+   */
+  function setUp(array $modules = array()) {
+    $this->profile = 'testing';
+    parent::setUp($modules);
+  }
+
+  /**
+   * Create, save, and return a Payment.
+   *
+   * @param integer $uid
+   *   The user ID of the payment's owner.
+   * @param PaymentMethod $payment_method
+   *   An optional payment method to set. Defaults to PaymentMethodUnavailable.
+   *
+   * @return Payment
+   */
+  static function paymentCreate($uid, PaymentMethod $payment_method = NULL) {
+    $payment_method = $payment_method ? $payment_method : new PaymentMethodUnavailable;
+    $payment = new Payment(array(
+      'currency_code' => 'XXX',
+      'description' => 'This is the payment description',
+      'finish_callback' => 'payment_test_finish_callback',
+      'method' => $payment_method,
+      'uid' => $uid,
+    ));
+    $payment->setLineItem(new PaymentLineItem(array(
+      'name' => 'foo',
+      'amount' => 1.0,
+      'tax_rate' => 0.1,
+    )));
+
+    return $payment;
+  }
+
+  /**
+   * Create, save, and return a PaymentMethod.
+   *
+   * @param integer $uid
+   *   The user ID of the payment method's owner.
+   * @param PaymentMethodController $controller
+   *   An optional controller to set. Defaults to
+   *   PaymentMethodControllerUnavailable.
+   *
+   * @return PaymentMethod
+   */
+  static function paymentMethodCreate($uid, PaymentMethodController $controller = NULL) {
+    $name = self::randomName();
+    $controller = $controller ? $controller : payment_method_controller_load('PaymentMethodControllerUnavailable');
+    $payment_method = new PaymentMethod(array(
+      'controller' => $controller,
+      'controller_data' => $controller->controller_data_defaults,
+      'name' => $name,
+      'title' => $name,
+      'uid' => $uid,
+    ));
+
+    return $payment_method;
+  }
+}
diff --git a/payment/tests/payment_test/payment_test.info b/payment/tests/payment_test/payment_test.info
index 3a5c67f..d295f06 100644
--- a/payment/tests/payment_test/payment_test.info
+++ b/payment/tests/payment_test/payment_test.info
@@ -6,18 +6,17 @@ dependencies[] = views
 dependencies[] = xtools
 package = Payment
 hidden = TRUE
-files[] = tests/PaymentActionHookAndCallbackWebTestCase.test
-files[] = tests/PaymentAmountFormElementWebTestCase.test
-files[] = tests/PaymentEntityPermissionWebTestCase.test
-files[] = tests/PaymentCallablesWebTestCase.test
-files[] = tests/PaymentLineItemFormElementWebTestCase.test
-files[] = tests/PaymentLineItemWebTestCase.test
-files[] = tests/PaymentMenuRouterItemPermissionWebTestCase.test
-files[] = tests/PaymentMethodEntityPermissionWebTestCase.test
-files[] = tests/PaymentMethodMenuRouterItemPermissionWebTestCase.test
-files[] = tests/PaymentStatusItemWebTestCase.test
-files[] = tests/PaymentTestUpdatePathWebTestCaseWithContent.test
-files[] = tests/PaymentTestUpdatePathWebTestCaseWithoutContent.test
-files[] = tests/PaymentUnavailableWebTestCase.test
-files[] = tests/PaymentValidationWebTestCase.test
-files[] = tests/PaymentWebTestCase.test
\ No newline at end of file
+files[] = tests/PaymentTestActionHookAndCallbackWebTestCase.test
+files[] = tests/PaymentTestCallablesWebTestCase.test
+files[] = tests/PaymentTestPaymentAmountFormElementWebTestCase.test
+files[] = tests/PaymentTestPaymentEntityPermissionWebTestCase.test
+files[] = tests/PaymentTestPaymentLineItemFormElementWebTestCase.test
+files[] = tests/PaymentTestPaymentLineItemWebTestCase.test
+files[] = tests/PaymentTestPaymentMenuRouterItemPermissionWebTestCase.test
+files[] = tests/PaymentTestPaymentMethodEntityPermissionWebTestCase.test
+files[] = tests/PaymentTestPaymentMethodMenuRouterItemPermissionWebTestCase.test
+files[] = tests/PaymentTestPaymentStatusItemWebTestCase.test
+files[] = tests/PaymentTestPaymentValidationWebTestCase.test
+files[] = tests/PaymentTestUpdatePathWithContentWebTestCase.test
+files[] = tests/PaymentTestUpdatePathWithoutContentWebTestCase.test
+files[] = tests/PaymentTestUnavailableWebTestCase.test
diff --git a/payment/tests/payment_test/tests/PaymentActionHookAndCallbackWebTestCase.test b/payment/tests/payment_test/tests/PaymentActionHookAndCallbackWebTestCase.test
deleted file mode 100644
index 9d804f4..0000000
--- a/payment/tests/payment_test/tests/PaymentActionHookAndCallbackWebTestCase.test
+++ /dev/null
@@ -1,49 +0,0 @@
-<?php
-
-/**
- * Tests action hook and callback invocations.
- */
-class PaymentActionHookAndCallbackTestWebTestCase extends PaymentWebTestCase {
-
-  static function getInfo() {
-    return array(
-      'name' => 'Action hook and callback invocations',
-      'group' => 'Payment',
-    );
-  }
-
-  function setUp(array $modules = array()) {
-    parent::setUp($modules + array('payment_test', 'paymentmethodbasic'));
-  }
-
-  /**
-   * Test whether all action hooks and callbacks are invoked.
-   */
-  function testActionHooksAndCallbacks() {
-    $payment_method = $this->paymentMethodCreate(1, payment_method_controller_load('PaymentMethodBasicController'));
-    $payment = $this->paymentCreate(1, $payment_method);
-
-    // Test hook_payment_validate(), hook_payment_pre_execute(),
-    // hook_payment_status_change(), and the finish callback.
-    $validation = FALSE;
-    try {
-      $payment->payment_test_payment_validate = TRUE;
-      $payment_method->validate($payment);
-    }
-    catch (PaymentValidationException $e) {
-      $validation = $e->getMessage() == 'payment_test';
-    }
-    unset($payment->payment_test_payment_validate);
-    $this->assertTrue($validation, 'hook_payment_validate() is invoked when validating a payment before execution.');
-    $payment->execute();
-    $this->assertTrue(isset($payment->payment_test_payment_pre_execute), 'hook_payment_pre_execute() is invoked before executing a payment.');
-    $this->assertTrue(isset($payment->payment_test_payment_status_change), 'hook_payment_status_change() is invoked before executing a payment.');
-    $this->assertTrue(isset($payment->payment_test_finish_callback), 'The finish callback is invoked after executing a payment.');
-
-    // Test hook_payment_form_alter().
-    $form_state = form_state_defaults();
-    $form = payment_form_embedded($form_state, $payment);
-    $this->assertTrue(isset($form['elements']['payment_test']), 'Form elements can be altered through hook_payment_form_alter().');
-    $this->assertTrue(in_array('payment_test', $form['submit']), 'Submit callbacks can be altered through hook_payment_form_alter().');
-  }
-}
\ No newline at end of file
diff --git a/payment/tests/payment_test/tests/PaymentAmountFormElementWebTestCase.test b/payment/tests/payment_test/tests/PaymentAmountFormElementWebTestCase.test
deleted file mode 100644
index 187b1b9..0000000
--- a/payment/tests/payment_test/tests/PaymentAmountFormElementWebTestCase.test
+++ /dev/null
@@ -1,58 +0,0 @@
-<?php
-
-/**
- * Tests the payment_line_item form element.
- */
-class PaymentAmountFormElementWebTestCase extends PaymentWebTestCase {
-
-  static function getInfo() {
-    return array(
-      'name' => 'Payment amount form element',
-      'group' => 'Payment',
-    );
-  }
-
-  function setUp(array $modules = array()) {
-    parent::setUp($modules + array('payment', 'payment_test'));
-  }
-
-  /**
-   * Test validation.
-   */
-  function testValidation() {
-    // Test valid values.
-    $values =  array(
-      'amount' => '49.95',
-    );
-    $this->drupalPost('payment_test-form-element-payment-amount', $values, t('Submit'));
-    $this->assertUrl('user', array(), 'A valid value higher than the default <em>#minimum_value</em> triggers form submission.');
-    $values =  array(
-      'amount' => '50,95',
-    );
-    $this->drupalPost('payment_test-form-element-payment-amount/50', $values, t('Submit'));
-    $this->assertUrl('user', array(), 'A valid value higher than an explicitely configured <em>#minimum_value</em> triggers form submission.');
-
-    // Test illegal characters.
-    $values =  array(
-      'amount' => $this->randomName(2),
-    );
-    $this->drupalPost('payment_test-form-element-payment-amount', $values, t('Submit'));
-    $this->assertText(t('The amount can only consist of a minus sign, decimals and one decimal mark.'), 'Non-numeric characters that are no period, comma, or minus sign throw a validation error.');
-
-    // Test multiple decimal marks.
-    $values =  array(
-      'amount' => '49,.95',
-    );
-    $this->drupalPost('payment_test-form-element-payment-amount', $values, t('Submit'));
-    $this->assertText(t('The amount can only consist of digits, optionally preceded by a minus sign and optionally preceded, separated or succeeded by a decimal separator.'), 'Multiple decimal marks throw a validation error.');
-
-    // Test the minimum value.
-    $values =  array(
-      'amount' => '49.95',
-    );
-    $this->drupalPost('payment_test-form-element-payment-amount/50', $values, t('Submit'));
-    $this->assertText(t('The minimum amount is !amount.', array(
-      '!amount' => payment_amount_human_readable(50, 'XXX'),
-    )), 'An amount below the minimum throws a validation error.');
-  }
-}
\ No newline at end of file
diff --git a/payment/tests/payment_test/tests/PaymentBillingInfoHookReturnValueWebTestCase.test b/payment/tests/payment_test/tests/PaymentBillingInfoHookReturnValueWebTestCase.test
deleted file mode 100644
index 1b810c7..0000000
--- a/payment/tests/payment_test/tests/PaymentBillingInfoHookReturnValueWebTestCase.test
+++ /dev/null
@@ -1,20 +0,0 @@
-<?php
-
-class PaymentBillingCallablesWebTestCase extends PaymentWebTestCase {
-
-  static function getInfo() {
-    return array(
-      'name' => "Callables",
-      'group' => 'Billing',
-      'dependencies' => array('paymentbilling', 'xtools'),
-    );
-  }
-
-  function setUp(array $modules = array()) {
-    parent::setUp($modules + array('xtools'));
-  }
-
-  function testCallables() {
-    $this->XtoolsAssertCallables('paymentbilling');
-  }
-}
\ No newline at end of file
diff --git a/payment/tests/payment_test/tests/PaymentCallablesWebTestCase.test b/payment/tests/payment_test/tests/PaymentCallablesWebTestCase.test
deleted file mode 100644
index 5926d98..0000000
--- a/payment/tests/payment_test/tests/PaymentCallablesWebTestCase.test
+++ /dev/null
@@ -1,20 +0,0 @@
-<?php
-
-class PaymentCallablesWebTestCase extends XtoolsWebTestCase {
-
-  static function getInfo() {
-    return array(
-      'name' => "Callables",
-      'group' => 'Payment',
-      'dependencies' => array('payment', 'payment_test', 'views', 'xtools'),
-    );
-  }
-
-  function setUp(array $modules = array()) {
-    parent::setUp($modules = array('xtools'));
-  }
-
-  function testCallables() {
-    $this->XtoolsAssertCallables(array('payment', 'payment_test'), array('drupal', 'payment', 'views', 'xtools'));
-  }
-}
\ No newline at end of file
diff --git a/payment/tests/payment_test/tests/PaymentEntityPermissionWebTestCase.test b/payment/tests/payment_test/tests/PaymentEntityPermissionWebTestCase.test
deleted file mode 100644
index ca1fcbe..0000000
--- a/payment/tests/payment_test/tests/PaymentEntityPermissionWebTestCase.test
+++ /dev/null
@@ -1,45 +0,0 @@
-<?php
-
-class PaymentEntityPermissionWebTestCase extends PaymentWebTestCase {
-
-  static function getInfo() {
-    return array(
-      'name' => 'Payment permissions',
-      'group' => 'Payment',
-      'dependencies' => array('payment', 'xtools'),
-    );
-  }
-
-  function setUp(array $modules = array()) {
-    parent::setUp($modules + array('payment', 'xtools'));
-  }
-
-  function testPaymentEntityPermissions() {
-    $payment_1 = $this->paymentCreate(1);
-    $payment_2 = $this->paymentCreate(2);
-
-    // Create a payment.
-    $this->XtoolsAssertEntityPermission(NULL, 'Payment', 'payment_access', 'create', array(), array(
-      'anonymous' => TRUE,
-      'authenticated_without_permissions' => TRUE,
-    ));
-
-    // Update a payment that belongs to user 1.
-    $this->XtoolsAssertEntityPermission($payment_1, 'Payment', 'payment_access', 'update', array('payment.payment.update.any'));
-
-    // Update a payment that belongs to user 2.
-    $this->XtoolsAssertEntityPermission($payment_2, 'Payment', 'payment_access', 'update', array('payment.payment.update.own'));
-
-    // Delete a payment that belongs to user 1.
-    $this->XtoolsAssertEntityPermission($payment_1, 'Payment', 'payment_access', 'delete', array('payment.payment.delete.any'));
-
-    // Delete a payment that belongs to user 2.
-    $this->XtoolsAssertEntityPermission($payment_2, 'Payment', 'payment_access', 'delete', array('payment.payment.delete.own'));
-
-    // View a payment that belongs to user 1.
-    $this->XtoolsAssertEntityPermission($payment_1, 'Payment', 'payment_access', 'view', array('payment.payment.view.any'));
-
-    // View a payment that belongs to user 2.
-    $this->XtoolsAssertEntityPermission($payment_2, 'Payment', 'payment_access', 'view', array('payment.payment.view.own'));
-  }
-}
\ No newline at end of file
diff --git a/payment/tests/payment_test/tests/PaymentLineItemFormElementWebTestCase.test b/payment/tests/payment_test/tests/PaymentLineItemFormElementWebTestCase.test
deleted file mode 100644
index a6f46b8..0000000
--- a/payment/tests/payment_test/tests/PaymentLineItemFormElementWebTestCase.test
+++ /dev/null
@@ -1,144 +0,0 @@
-<?php
-
-/**
- * Tests the payment_line_item form element.
- */
-class PaymentLineItemFormElementWebTestCase extends PaymentWebTestCase {
-
-  static function getInfo() {
-    return array(
-      'name' => 'Payment line item form element',
-      'group' => 'Payment',
-    );
-  }
-
-  function setUp(array $modules = array()) {
-    parent::setUp($modules + array('payment', 'payment_test'));
-    $this->PaymentLineItemData = array(
-      'line_item[container_0][amount]' => '10.0',
-      'line_item[container_0][description]' => 'foo',
-      'line_item[container_0][name]' => 'bar',
-      'line_item[container_0][quantity]' => '1',
-      'line_item[container_0][tax_rate]' => '10',
-    );
-  }
-
-  /**
-   * Test the presence of widget's input elements.
-   */
-  function LineItemElements($delta_max = 0) {
-    for ($delta = 0; $delta <= $delta_max; $delta++) {
-      foreach (array('amount', 'description', 'name', 'quantity', 'tax-rate') as $name) {
-        $elements = $this->xpath('//input[@id="edit-line-item-container-' . $delta . '-' . $name . '"]');
-        $this->assertTrue(isset($elements[0]), "Payment line item configuration widget contains <em>$name</em> element for line item $delta.");
-      }
-    }
-  }
-
-  /**
-   * Test the presence of widget's submit button.
-   */
-  function SubmitButton($present) {
-    $elements = $this->xpath('//input[@id="payment-ajax-replace"]');
-    if ($present) {
-      $this->assertTrue(isset($elements[0]), "Payment line item configuration widget contains an <em>Add a line item</em> button if the number if line items is less than the widget's cardinality.");
-    }
-    else {
-      $this->assertFalse(isset($elements[0]), 'Payment line item configuration widget contains no <em>Add a line item</em> button.');
-    }
-  }
-
-  /**
-   * Test a regular submission.
-   */
-  function testSubmission() {
-    $this->drupalGet('payment_test-form-element-payment-line-item');
-    $this->LineItemElements();
-    $this->SubmitButton(TRUE);
-    $this->drupalPost(NULL, array(), t('Add a line item'));
-    $this->LineItemElements(1);
-    $this->SubmitButton(FALSE);
-  }
-
-  /**
-   * Test an AJAX submission.
-   */
-  function testAJAXSubmission() {
-    $this->drupalPostAJAX('payment_test-form-element-payment-line-item', array(), 'payment-line-item', NULL, array(), array(), 'payment-test-form-payment-line-item');
-    $this->LineItemElements(1);
-    $this->SubmitButton(FALSE);
-  }
-
-  /**
-   * Test default value handling.
-   */
-  function testDefaultValues() {
-    $this->drupalGet('payment_test-form-element-payment-line-item/default-values');
-    foreach (payment_test_default_line_items() as $delta => $line_item) {
-      $properties = array(
-        'amount' => $line_item->amount,
-        'description' => $line_item->description,
-        'name' => $line_item->name,
-        'quantity' => $line_item->quantity,
-        'tax_rate' => $line_item->tax_rate * 100,
-      );
-      foreach ($properties as $property => $value) {
-        $elements = $this->xpath('//input[@id="edit-line-item-container-' . $delta . '-' . drupal_clean_css_identifier($property) . '" and @value="' . $value . '"]');
-        $this->assertTrue(isset($elements[0]), "The element contains the <em>$property</em> value for default line item $delta.");
-      }
-    }
-  }
-
-  /**
-   * Test validation.
-   */
-  function testValidation() {
-    // Test valid values.
-    $this->drupalPost('payment_test-form-element-payment-line-item', $this->PaymentLineItemData, t('Submit'));
-    $this->assertUrl('user', array(), 'Valid values trigger form submission.');
-
-    // Test leaving some elements empty.
-    $values = array(
-      'line_item[container_0][description]' => '',
-    ) + $this->PaymentLineItemData;
-    $this->drupalPost('payment_test-form-element-payment-line-item', $values, t('Submit'));
-    $this->assertRaw(t('%title is required, or leave all fields for this line item empty.', array(
-      '%title' => t('Description'),
-    )), "Partially filling in a line item's element throws a validation error.");
-
-    // Test a non-integer quantity.
-    $values =  array(
-      'line_item[container_0][quantity]' => $this->randomName(2),
-    );
-    $this->drupalPost('payment_test-form-element-payment-line-item', $values, t('Submit'));
-    $this->assertText(t('Quantity should be a positive integer.'), 'A non-integer amount throws a validation error.');
-
-    // Test a non-numeric tax rate.
-    $values =  array(
-      'line_item[container_0][tax_rate]' => $this->randomName(2),
-    );
-    $this->drupalPost('payment_test-form-element-payment-line-item', $values, t('Submit'));
-    $this->assertFieldByXPath('//input[@id="edit-line-item-container-0-tax-rate" and contains(@class, "error")]', NULL, 'A non-numeric tax rate throws a validation error.');
-
-    // Test a negative tax rate.
-    $values =  array(
-      'line_item[container_0][tax_rate]' => '-10',
-    );
-    $this->drupalPost('payment_test-form-element-payment-line-item', $values, t('Submit'));
-    $this->assertFieldByXPath('//input[@id="edit-line-item-container-0-tax-rate" and contains(@class, "error")]', NULL, 'A negative tax rate throws a validation error.');
-
-    // Test a float tax rate that uses a period.
-    $values =  array(
-      'line_item[container_0][tax_rate]' => '19.6',
-    );
-    $this->drupalPost('payment_test-form-element-payment-line-item', $values, t('Submit'));
-    $this->assertFieldByXPath('//input[@id="edit-line-item-container-0-tax-rate" and not(contains(@class, "error"))]', NULL, 'A float tax rate that includes a period is valid.');
-
-    // Test a float tax rate that uses a comma.
-    $values =  array(
-      'line_item[container_0][tax_rate]' => '19,6',
-    );
-    $this->drupalPost('payment_test-form-element-payment-line-item', $values, t('Submit'));
-    $this->assertFieldByXPath('//input[@id="edit-line-item-container-0-tax-rate" and not(contains(@class, "error"))]', NULL, 'A float tax rate that includes a comma is valid.');
-  }
-}
\ No newline at end of file
diff --git a/payment/tests/payment_test/tests/PaymentLineItemWebTestCase.test b/payment/tests/payment_test/tests/PaymentLineItemWebTestCase.test
deleted file mode 100644
index 195e694..0000000
--- a/payment/tests/payment_test/tests/PaymentLineItemWebTestCase.test
+++ /dev/null
@@ -1,69 +0,0 @@
-<?php
-
-/**
- * Test line item handling.
- */
-class PaymentLineItemWebTestCase extends PaymentWebTestCase {
-
-  static function getInfo() {
-    return array(
-      'name' => 'Payment line item handling',
-      'group' => 'Payment',
-    );
-  }
-
-  function setUp(array $modules = array()) {
-    parent::setUp($modules + array('payment_test'));
-  }
-
-  /**
-   * Test line item handling.
-   */
-  function testPaymentLineItemHandling() {
-    $payment = new Payment;
-    $payment->setLineItem(new PaymentLineItem(array(
-      'name' => 'foo',
-      'amount' => 19.11,
-      'tax_rate' => 0.1,
-    )));
-
-    // Test Payment::setLineItem();
-    $this->assertTrue($payment->line_items['foo']->name == 'foo', 'Payment::setLineItem() adds a PaymentLineItem object to Payment::line_items.');
-
-    // Test Payment::unitAmount() without tax.
-    $this->assertTrue($payment->line_items['foo']->unitAmount(FALSE) == 19.11, 'Payment::unitAmount() returns amount excluding tax.');
-
-    // Test Payment::unitAmount() with tax.
-    $this->assertTrue($payment->line_items['foo']->unitAmount(TRUE) == 21.021, 'Payment::unitAmount() returns amount including tax.');
-
-    // Test Payment::totalAmount() without tax.
-    $this->assertTrue($payment->totalAmount(FALSE) == 19.11, 'Payment::totalAmount() returns amount excluding tax.');
-
-    $payment->setLineItem(new PaymentLineItem(array(
-      'name' => 'bar',
-      'amount' => 19.78,
-    )));
-
-    // Test Payment::totalAmount() without passed on amounts.
-    $this->assertTrue($payment->totalAmount(TRUE) == 40.801, 'Payment::totalAmount() adds up Payment::line_items.');
-
-    $payment->setLineItem(new PaymentLineItem(array(
-      'name' => 'beer',
-      'amount' => 47.11,
-    )));
-
-    // Test Payment::totalAmount() with passed on amounts.
-    $line_items = $payment->getLineItems('payment_test');
-    $this->assertTrue($payment->totalAmount(TRUE, $line_items) == 40.801, 'Payment::totalAmount() adds up only passed on line items.');
-
-    // Test payment_line_item_get_specific() and whether
-    // Payment::getLineItems() can get line items that are not exposed
-    // through hook_payment_line_item_info().
-    $line_items = $payment->getLineItems('beer');
-    $this->assertTrue($payment->totalAmount(TRUE, $line_items) == 47.11, 'payment_line_item_get_specific() only returns the requested line item.');
-
-    // Test payment_line_item_get_all().
-    $line_items = $payment->getLineItems('payment_all');
-    $this->assertTrue(count($line_items) == 3, 'payment_line_item_get_all() returns all line items.');
-  }
-}
\ No newline at end of file
diff --git a/payment/tests/payment_test/tests/PaymentMenuRouterItemPermissionWebTestCase.test b/payment/tests/payment_test/tests/PaymentMenuRouterItemPermissionWebTestCase.test
deleted file mode 100644
index 39a5cad..0000000
--- a/payment/tests/payment_test/tests/PaymentMenuRouterItemPermissionWebTestCase.test
+++ /dev/null
@@ -1,51 +0,0 @@
-<?php
-
-class PaymentMenuRouterItemPermissionWebTestCase extends PaymentWebTestCase {
-
-  static function getInfo() {
-    return array(
-      'name' => 'Payment menu router item permissions',
-      'group' => 'Payment',
-      'dependencies' => array('payment', 'paymentmethodbasic', 'xtools'),
-    );
-  }
-
-  function setUp(array $modules = array()) {
-    parent::setUp($modules + array('payment', 'paymentmethodbasic', 'xtools'));
-  }
-
-  function testPaymentMenuRouterItemPermissions() {
-    $payment_method = $this->paymentMethodCreate(2, payment_method_controller_load('PaymentMethodBasicController'));
-    entity_save('payment_method', $payment_method);
-    $payment = $this->paymentCreate(2, $payment_method);
-    entity_save('payment', $payment);
-
-    // Test the global configuration page.
-    $this->XtoolsAssertMenuRouterItemPermission('admin/config/services/payment/global', array('payment.global.administer'));
-
-    // Test the payment view page.
-    $this->XtoolsAssertMenuRouterItemPermission('payment/' . $payment->pid, array('payment.payment.view.any'));
-
-    // Test the payment edit page.
-    $this->XtoolsAssertMenuRouterItemPermission('payment/' . $payment->pid . '/edit', array('payment.payment.update.any'));
-
-    // Test the payment delete page.
-    $this->XtoolsAssertMenuRouterItemPermission('payment/' . $payment->pid . '/delete', array('payment.payment.delete.any'));
-
-    // Test the administrative payment overview page (Views disabled).
-    $this->XtoolsAssertMenuRouterItemPermission('admin/content/payment', array('payment.payment.view.any'), array(), 'Views disabled');
-
-    // Test a user's payment overview page (Views disabled).
-    $this->XtoolsAssertMenuRouterItemPermission('user/2/payment', array('payment.payment.view.own'), array(), 'Views disabled');
-
-    // Enable Views.
-    $this->assertTrue(module_enable(array('views')), 'Enabled modules: <em>views</em>');
-    $this->resetAll();
-
-    // Test the administrative payment overview page (Views enabled).
-    $this->XtoolsAssertMenuRouterItemPermission('admin/content/payment', array('payment.payment.view.any'), array(), 'Views enabled');
-
-    // Test a user's payment overview page (Views enabled).
-    $this->XtoolsAssertMenuRouterItemPermission('user/2/payment', array('payment.payment.view.own'), array(), 'Views enabled');
-  }
-}
\ No newline at end of file
diff --git a/payment/tests/payment_test/tests/PaymentMethodEntityPermissionWebTestCase.test b/payment/tests/payment_test/tests/PaymentMethodEntityPermissionWebTestCase.test
deleted file mode 100644
index cc70e1c..0000000
--- a/payment/tests/payment_test/tests/PaymentMethodEntityPermissionWebTestCase.test
+++ /dev/null
@@ -1,93 +0,0 @@
-<?php
-
-class PaymentMethodEntityPermissionWebTestCase extends PaymentWebTestCase {
-
-  static function getInfo() {
-    return array(
-      'name' => 'Payment method permissions',
-      'group' => 'Payment',
-      'dependencies' => array('payment', 'paymentmethodbasic', 'xtools'),
-    );
-  }
-
-  function setUp(array $modules = array()) {
-    parent::setUp($modules + array('payment', 'paymentmethodbasic', 'xtools'));
-  }
-
-  function testPaymentMethodEntityPermissions() {
-    // Create a new payment method.
-    $this->XtoolsAssertEntityPermission($this->paymentMethodCreate(0, payment_method_controller_load('PaymentMethodBasicController')), 'payment method', 'payment_method_access', 'create', array('payment.payment_method.create.PaymentMethodBasicController'));
-
-    // Update a payment method that belongs to user 1.
-    $this->XtoolsAssertEntityPermission($this->paymentMethodCreate(1, payment_method_controller_load('PaymentMethodBasicController')), 'payment method', 'payment_method_access', 'update', array('payment.payment_method.update.any'));
-
-    // Update a payment method that belongs to user 2.
-    $this->XtoolsAssertEntityPermission($this->paymentMethodCreate(2, payment_method_controller_load('PaymentMethodBasicController')), 'payment method', 'payment_method_access', 'update', array('payment.payment_method.update.own'));
-
-    // Delete a payment method that belongs to user 1.
-    $this->XtoolsAssertEntityPermission($this->paymentMethodCreate(1, payment_method_controller_load('PaymentMethodBasicController')), 'payment method', 'payment_method_access', 'delete', array('payment.payment_method.delete.any'));
-
-    // Delete a payment method that belongs to user 2.
-    $this->XtoolsAssertEntityPermission($this->paymentMethodCreate(2, payment_method_controller_load('PaymentMethodBasicController')), 'payment method', 'payment_method_access', 'delete', array('payment.payment_method.delete.own'));
-
-    // Enable an enabled payment method that belongs to user 1.
-    $payment_method = $this->paymentMethodCreate(1, payment_method_controller_load('PaymentMethodBasicController'));
-    $this->XtoolsAssertEntityPermission($payment_method, 'enabled payment method', 'payment_method_access', 'enable', array('payment.payment_method.update.any'), array(
-      'root' => FALSE,
-      'authenticated_with_permissions' => FALSE,
-    ));
-
-    // Enable an enabled payment method that belongs to user 2.
-    $payment_method = $this->paymentMethodCreate(2, payment_method_controller_load('PaymentMethodBasicController'));
-    $this->XtoolsAssertEntityPermission($payment_method, 'enabled payment method', 'payment_method_access', 'enable', array('payment.payment_method.update.own'), array(
-      'root' => FALSE,
-      'authenticated_with_permissions' => FALSE,
-    ));
-
-    // Enable a disabled payment method that belongs to user 1.
-    $payment_method = $this->paymentMethodCreate(1, payment_method_controller_load('PaymentMethodBasicController'));
-    $payment_method->enabled = FALSE;
-    $this->XtoolsAssertEntityPermission($payment_method, 'disabled payment method', 'payment_method_access', 'enable', array('payment.payment_method.update.any'));
-
-    // Enable a disabled payment method that belongs to user 2.
-    $payment_method = $this->paymentMethodCreate(2, payment_method_controller_load('PaymentMethodBasicController'));
-    $payment_method->enabled = FALSE;
-    $this->XtoolsAssertEntityPermission($payment_method, 'disabled payment method', 'payment_method_access', 'enable', array('payment.payment_method.update.own'));
-
-    // Disable a disabled payment method that belongs to user 1.
-    $payment_method = $this->paymentMethodCreate(1, payment_method_controller_load('PaymentMethodBasicController'));
-    $payment_method->enabled = FALSE;
-    $this->XtoolsAssertEntityPermission($payment_method, 'disabled payment method', 'payment_method_access', 'disable', array('payment.payment_method.update.any'), array(
-      'root' => FALSE,
-      'authenticated_with_permissions' => FALSE,
-    ));
-
-    // Disable a disabled payment method that belongs to user 2.
-    $payment_method = $this->paymentMethodCreate(2, payment_method_controller_load('PaymentMethodBasicController'));
-    $payment_method->enabled = FALSE;
-    $this->XtoolsAssertEntityPermission($payment_method, 'disabled payment method', 'payment_method_access', 'disable', array('payment.payment_method.update.own'), array(
-      'root' => FALSE,
-      'authenticated_with_permissions' => FALSE,
-    ));
-
-    // Disable an enabled payment method that belongs to user 1.
-    $payment_method = $this->paymentMethodCreate(1, payment_method_controller_load('PaymentMethodBasicController'));
-    $this->XtoolsAssertEntityPermission($payment_method, 'disabled payment method', 'payment_method_access', 'disable', array('payment.payment_method.update.any'));
-
-    // Enable am enabled payment method that belongs to user 2.
-    $payment_method = $this->paymentMethodCreate(2, payment_method_controller_load('PaymentMethodBasicController'));
-    $this->XtoolsAssertEntityPermission($payment_method, 'disabled payment method', 'payment_method_access', 'disable', array('payment.payment_method.update.own'));
-
-    // Clone a payment method that belongs to user 1.
-    $this->XtoolsAssertEntityPermission($this->paymentMethodCreate(1, payment_method_controller_load('PaymentMethodBasicController')), 'payment method', 'payment_method_access', 'clone', array('payment.payment_method.view.any', 'payment.payment_method.create.PaymentMethodBasicController'));
-
-    // Clone a payment method that belongs to user 2.
-    $this->XtoolsAssertEntityPermission($this->paymentMethodCreate(2, payment_method_controller_load('PaymentMethodBasicController')), 'payment method', 'payment_method_access', 'clone', array('payment.payment_method.view.own', 'payment.payment_method.create.PaymentMethodBasicController'));
-
-    // View a payment method that belongs to user 1.
-    $this->XtoolsAssertEntityPermission($this->paymentMethodCreate(1, payment_method_controller_load('PaymentMethodBasicController')), 'payment method', 'payment_method_access', 'view', array('payment.payment_method.view.any'));
-
-    // View a payment method that belongs to user 2.
-    $this->XtoolsAssertEntityPermission($this->paymentMethodCreate(2, payment_method_controller_load('PaymentMethodBasicController')), 'payment method', 'payment_method_access', 'view', array('payment.payment_method.view.own'));
-  }
-}
\ No newline at end of file
diff --git a/payment/tests/payment_test/tests/PaymentMethodMenuRouterItemPermissionWebTestCase.test b/payment/tests/payment_test/tests/PaymentMethodMenuRouterItemPermissionWebTestCase.test
deleted file mode 100644
index 42e315e..0000000
--- a/payment/tests/payment_test/tests/PaymentMethodMenuRouterItemPermissionWebTestCase.test
+++ /dev/null
@@ -1,57 +0,0 @@
-<?php
-
-class PaymentMethodMenuRouterItemPermissionWebTestCase extends PaymentWebTestCase {
-
-  static function getInfo() {
-    return array(
-      'name' => 'Payment method menu router item permissions',
-      'group' => 'Payment',
-      'dependencies' => array('payment', 'paymentmethodbasic', 'xtools'),
-    );
-  }
-
-  function setUp(array $modules = array()) {
-    parent::setUp($modules + array('payment', 'paymentmethodbasic', 'xtools'));
-  }
-
-  function testPaymentMethodMenuRouterItemPermissions() {
-    $payment_method_1 = $this->paymentMethodCreate(1, payment_method_controller_load('PaymentMethodBasicController'));
-    entity_save('payment_method', $payment_method_1);
-    $payment_method_2 = $this->paymentMethodCreate(2, payment_method_controller_load('PaymentMethodBasicController'));
-    entity_save('payment_method', $payment_method_2);
-
-    // Test the payment method overview (Views disabled).
-    $this->XtoolsAssertMenuRouterItemPermission('admin/config/services/payment/method', array('payment.payment_method.view.any'), array(), 'Views disabled');
-
-    // Enable Views.
-    $this->assertTrue(module_enable(array('views')), 'Enabled modules: <em>views</em>');
-    $this->resetAll();
-
-    // Test the payment method overview (Views enabled).
-    $this->XtoolsAssertMenuRouterItemPermission('admin/config/services/payment/method', array('payment.payment_method.view.any'), array(), 'Views enabled');
-
-    // Test the payment method controller selection page.
-    $this->XtoolsAssertMenuRouterItemPermission('admin/config/services/payment/method/add', array('payment.payment_method.create.PaymentMethodBasicController'));
-
-    // Test the payment method add page.
-    $this->XtoolsAssertMenuRouterItemPermission('admin/config/services/payment/method/add/PaymentMethodBasicController', array('payment.payment_method.create.PaymentMethodBasicController'));
-
-    // Test the payment method edit page for a payment method that belongs to user 1.
-    $this->XtoolsAssertMenuRouterItemPermission('admin/config/services/payment/method/' . $payment_method_1->pmid . '/edit', array('payment.payment_method.update.any'));
-
-    // Test the payment method edit page for a payment method that belongs to user 2.
-    $this->XtoolsAssertMenuRouterItemPermission('admin/config/services/payment/method/' . $payment_method_2->pmid . '/edit', array('payment.payment_method.update.own'));
-
-    // Test the payment method delete page for a payment method that belongs to user 1.
-    $this->XtoolsAssertMenuRouterItemPermission('admin/config/services/payment/method/' . $payment_method_1->pmid . '/delete', array('payment.payment_method.delete.any'));
-
-    // Test the payment method delete page for a payment method that belongs to user 2.
-    $this->XtoolsAssertMenuRouterItemPermission('admin/config/services/payment/method/' . $payment_method_2->pmid . '/delete', array('payment.payment_method.delete.own'));
-
-    // Test the payment method clone page for a payment method that belongs to user 1.
-    $this->XtoolsAssertMenuRouterItemPermission('admin/config/services/payment/method/' . $payment_method_1->pmid . '/clone', array('payment.payment_method.view.any', 'payment.payment_method.create.' . $payment_method_1->controller->name));
-
-    // Test the payment method clone page for a payment method that belongs to user 2.
-    $this->XtoolsAssertMenuRouterItemPermission('admin/config/services/payment/method/' . $payment_method_2->pmid . '/clone', array('payment.payment_method.view.own', 'payment.payment_method.create.' . $payment_method_2->controller->name));
-  }
-}
\ No newline at end of file
diff --git a/payment/tests/payment_test/tests/PaymentStatusItemWebTestCase.test b/payment/tests/payment_test/tests/PaymentStatusItemWebTestCase.test
deleted file mode 100644
index 9e27b76..0000000
--- a/payment/tests/payment_test/tests/PaymentStatusItemWebTestCase.test
+++ /dev/null
@@ -1,33 +0,0 @@
-<?php
-
-/**
- * Test payment status item handling.
- */
-class PaymentStatusItemWebTestCase extends PaymentWebTestCase {
-
-  static function getInfo() {
-    return array(
-      'name' => 'Payment status item handling',
-      'group' => 'Payment',
-    );
-  }
-
-  /**
-   * Implements DrupalWebTestCase::setUp().
-   */
-  function setUp(array $modules = array()) {
-    parent::setUp($modules = array('payment'));
-  }
-
-  /**
-   * Test payment status item handling.
-   */
-  function testPaymentStatusItem() {
-    $payment = new Payment;
-    $status_pending = new PaymentStatusItem(PAYMENT_STATUS_PENDING);
-    $status_success = new PaymentStatusItem(PAYMENT_STATUS_SUCCESS);
-    $payment->setStatus($status_pending);
-    $payment->setStatus($status_success);
-    $this->assertTrue($payment->getStatus() === $status_success, 'Payment::setStatus() sets status items in the right order and Payment::getStatus() retrieves them.');
-  }
-}
\ No newline at end of file
diff --git a/payment/tests/payment_test/tests/PaymentTestActionHookAndCallbackWebTestCase.test b/payment/tests/payment_test/tests/PaymentTestActionHookAndCallbackWebTestCase.test
new file mode 100644
index 0000000..738154d
--- /dev/null
+++ b/payment/tests/payment_test/tests/PaymentTestActionHookAndCallbackWebTestCase.test
@@ -0,0 +1,57 @@
+<?php
+
+/**
+ * @file
+ * Contains class PaymentTestActionHookAndCallbackWebTestCase.
+ */
+
+/**
+ * Tests action hook and callback invocations.
+ */
+class PaymentTestActionHookAndCallbackWebTestCase extends PaymentWebTestCase {
+
+  static function getInfo() {
+    return array(
+      'name' => 'Action hook and callback invocations',
+      'group' => 'Payment',
+    );
+  }
+
+  /**
+   * Overrides parent::setUp().
+   */
+  function setUp(array $modules = array()) {
+    parent::setUp($modules + array('payment_test', 'paymentmethodbasic'));
+  }
+
+  /**
+   * Test whether all action hooks and callbacks are invoked.
+   */
+  function testActionHooksAndCallbacks() {
+    $payment_method = $this->paymentMethodCreate(1, payment_method_controller_load('PaymentMethodBasicController'));
+    $payment = $this->paymentCreate(1, $payment_method);
+
+    // Test hook_payment_validate(), hook_payment_pre_execute(),
+    // hook_payment_status_change(), and the finish callback.
+    $validation = FALSE;
+    try {
+      $payment->payment_test_payment_validate = TRUE;
+      $payment_method->validate($payment);
+    }
+    catch (PaymentValidationException $e) {
+      $validation = $e->getMessage() == 'payment_test';
+    }
+    unset($payment->payment_test_payment_validate);
+    $this->assertTrue($validation, 'hook_payment_validate() is invoked when validating a payment before execution.');
+    $payment->execute();
+    $this->assertTrue(isset($payment->payment_test_payment_pre_execute), 'hook_payment_pre_execute() is invoked before executing a payment.');
+    $this->assertTrue(isset($payment->payment_test_payment_status_change), 'hook_payment_status_change() is invoked before executing a payment.');
+    $this->assertTrue(isset($payment->payment_test_finish_callback), 'The finish callback is invoked after executing a payment.');
+
+    // Test hook_payment_form_alter().
+    $form_state = form_state_defaults();
+    $form = payment_form_embedded($form_state, $payment);
+    $this->assertTrue(isset($form['elements']['payment_test']), 'Form elements can be altered through hook_payment_form_alter().');
+    $this->assertTrue(in_array('payment_test', $form['submit']), 'Submit callbacks can be altered through hook_payment_form_alter().');
+  }
+}
diff --git a/payment/tests/payment_test/tests/PaymentTestCallablesWebTestCase.test b/payment/tests/payment_test/tests/PaymentTestCallablesWebTestCase.test
new file mode 100644
index 0000000..3fec9ca
--- /dev/null
+++ b/payment/tests/payment_test/tests/PaymentTestCallablesWebTestCase.test
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ * @file
+ * Contains class PaymentTestCallablesWebTestCase.
+ */
+
+/**
+ * Tests implementations of callables.
+ */
+class PaymentTestCallablesWebTestCase extends XtoolsWebTestCase {
+
+  static function getInfo() {
+    return array(
+      'name' => 'Hook and callback implementations',
+      'group' => 'Payment',
+      'dependencies' => array('payment', 'payment_test', 'views', 'xtools'),
+    );
+  }
+
+  /**
+   * Overrides parent::setUp().
+   */
+  function setUp(array $modules = array()) {
+    parent::setUp($modules = array('xtools'));
+  }
+
+  function testCallables() {
+    $this->XtoolsAssertCallables(array('payment', 'payment_test'), array('drupal', 'payment', 'views', 'xtools'));
+  }
+}
diff --git a/payment/tests/payment_test/tests/PaymentTestPaymentAmountFormElementWebTestCase.test b/payment/tests/payment_test/tests/PaymentTestPaymentAmountFormElementWebTestCase.test
new file mode 100644
index 0000000..16a95aa
--- /dev/null
+++ b/payment/tests/payment_test/tests/PaymentTestPaymentAmountFormElementWebTestCase.test
@@ -0,0 +1,66 @@
+<?php
+
+/**
+ * @file
+ * Contains class PaymentTestPaymentAmountFormElementWebTestCase.
+ */
+
+/**
+ * Tests the payment_line_item form element.
+ */
+class PaymentTestPaymentAmountFormElementWebTestCase extends PaymentWebTestCase {
+
+  static function getInfo() {
+    return array(
+      'name' => 'Payment amount form element',
+      'group' => 'Payment',
+    );
+  }
+
+  /**
+   * Overrides parent::setUp().
+   */
+  function setUp(array $modules = array()) {
+    parent::setUp($modules + array('payment', 'payment_test'));
+  }
+
+  /**
+   * Test validation.
+   */
+  function testValidation() {
+    // Test valid values.
+    $values =  array(
+      'amount' => '49.95',
+    );
+    $this->drupalPost('payment_test-form-element-payment-amount', $values, t('Submit'));
+    $this->assertUrl('user', array(), 'A valid value higher than the default <em>#minimum_value</em> triggers form submission.');
+    $values =  array(
+      'amount' => '50,95',
+    );
+    $this->drupalPost('payment_test-form-element-payment-amount/50', $values, t('Submit'));
+    $this->assertUrl('user', array(), 'A valid value higher than an explicitely configured <em>#minimum_value</em> triggers form submission.');
+
+    // Test illegal characters.
+    $values =  array(
+      'amount' => $this->randomName(2),
+    );
+    $this->drupalPost('payment_test-form-element-payment-amount', $values, t('Submit'));
+    $this->assertText(t('The amount can only consist of a minus sign, decimals and one decimal mark.'), 'Non-numeric characters that are no period, comma, or minus sign throw a validation error.');
+
+    // Test multiple decimal marks.
+    $values =  array(
+      'amount' => '49,.95',
+    );
+    $this->drupalPost('payment_test-form-element-payment-amount', $values, t('Submit'));
+    $this->assertText(t('The amount can only consist of digits, optionally preceded by a minus sign and optionally preceded, separated or succeeded by a decimal separator.'), 'Multiple decimal marks throw a validation error.');
+
+    // Test the minimum value.
+    $values =  array(
+      'amount' => '49.95',
+    );
+    $this->drupalPost('payment_test-form-element-payment-amount/50', $values, t('Submit'));
+    $this->assertText(t('The minimum amount is !amount.', array(
+      '!amount' => payment_amount_human_readable(50, 'XXX'),
+    )), 'An amount below the minimum throws a validation error.');
+  }
+}
diff --git a/payment/tests/payment_test/tests/PaymentTestPaymentEntityPermissionWebTestCase.test b/payment/tests/payment_test/tests/PaymentTestPaymentEntityPermissionWebTestCase.test
new file mode 100644
index 0000000..eb92f47
--- /dev/null
+++ b/payment/tests/payment_test/tests/PaymentTestPaymentEntityPermissionWebTestCase.test
@@ -0,0 +1,56 @@
+<?php
+
+/**
+ * @file
+ * Contains class PaymentTestPaymentEntityPermissionWebTestCase.
+ */
+
+/**
+ * Tests payment entity permissions.
+ */
+class PaymentTestPaymentEntityPermissionWebTestCase extends PaymentWebTestCase {
+
+  static function getInfo() {
+    return array(
+      'name' => 'Payment permissions',
+      'group' => 'Payment',
+      'dependencies' => array('payment', 'xtools'),
+    );
+  }
+
+  /**
+   * Overrides parent::setUp().
+   */
+  function setUp(array $modules = array()) {
+    parent::setUp($modules + array('payment', 'xtools'));
+  }
+
+  function testPaymentEntityPermissions() {
+    $payment_1 = $this->paymentCreate(1);
+    $payment_2 = $this->paymentCreate(2);
+
+    // Create a payment.
+    $this->XtoolsAssertEntityPermission(NULL, 'Payment', 'payment_access', 'create', array(), array(
+      'anonymous' => TRUE,
+      'authenticated_without_permissions' => TRUE,
+    ));
+
+    // Update a payment that belongs to user 1.
+    $this->XtoolsAssertEntityPermission($payment_1, 'Payment', 'payment_access', 'update', array('payment.payment.update.any'));
+
+    // Update a payment that belongs to user 2.
+    $this->XtoolsAssertEntityPermission($payment_2, 'Payment', 'payment_access', 'update', array('payment.payment.update.own'));
+
+    // Delete a payment that belongs to user 1.
+    $this->XtoolsAssertEntityPermission($payment_1, 'Payment', 'payment_access', 'delete', array('payment.payment.delete.any'));
+
+    // Delete a payment that belongs to user 2.
+    $this->XtoolsAssertEntityPermission($payment_2, 'Payment', 'payment_access', 'delete', array('payment.payment.delete.own'));
+
+    // View a payment that belongs to user 1.
+    $this->XtoolsAssertEntityPermission($payment_1, 'Payment', 'payment_access', 'view', array('payment.payment.view.any'));
+
+    // View a payment that belongs to user 2.
+    $this->XtoolsAssertEntityPermission($payment_2, 'Payment', 'payment_access', 'view', array('payment.payment.view.own'));
+  }
+}
diff --git a/payment/tests/payment_test/tests/PaymentTestPaymentLineItemFormElementWebTestCase.test b/payment/tests/payment_test/tests/PaymentTestPaymentLineItemFormElementWebTestCase.test
new file mode 100644
index 0000000..bc03f15
--- /dev/null
+++ b/payment/tests/payment_test/tests/PaymentTestPaymentLineItemFormElementWebTestCase.test
@@ -0,0 +1,152 @@
+<?php
+
+/**
+ * @file
+ * Contains class PaymentTestPaymentLineItemFormElementWebTestCase.
+ */
+
+/**
+ * Tests the payment_line_item form element.
+ */
+class PaymentTestPaymentLineItemFormElementWebTestCase extends PaymentWebTestCase {
+
+  static function getInfo() {
+    return array(
+      'name' => 'Payment line item form element',
+      'group' => 'Payment',
+    );
+  }
+
+  /**
+   * Overrides parent::setUp().
+   */
+  function setUp(array $modules = array()) {
+    parent::setUp($modules + array('payment', 'payment_test'));
+    $this->PaymentLineItemData = array(
+      'line_item[container_0][amount]' => '10.0',
+      'line_item[container_0][description]' => 'foo',
+      'line_item[container_0][name]' => 'bar',
+      'line_item[container_0][quantity]' => '1',
+      'line_item[container_0][tax_rate]' => '10',
+    );
+  }
+
+  /**
+   * Test the presence of widget's input elements.
+   */
+  function LineItemElements($delta_max = 0) {
+    for ($delta = 0; $delta <= $delta_max; $delta++) {
+      foreach (array('amount', 'description', 'name', 'quantity', 'tax-rate') as $name) {
+        $elements = $this->xpath('//input[@id="edit-line-item-container-' . $delta . '-' . $name . '"]');
+        $this->assertTrue(isset($elements[0]), "Payment line item configuration widget contains <em>$name</em> element for line item $delta.");
+      }
+    }
+  }
+
+  /**
+   * Test the presence of widget's submit button.
+   */
+  function SubmitButton($present) {
+    $elements = $this->xpath('//input[@id="payment-ajax-replace"]');
+    if ($present) {
+      $this->assertTrue(isset($elements[0]), "Payment line item configuration widget contains an <em>Add a line item</em> button if the number if line items is less than the widget's cardinality.");
+    }
+    else {
+      $this->assertFalse(isset($elements[0]), 'Payment line item configuration widget contains no <em>Add a line item</em> button.');
+    }
+  }
+
+  /**
+   * Test a regular submission.
+   */
+  function testSubmission() {
+    $this->drupalGet('payment_test-form-element-payment-line-item');
+    $this->LineItemElements();
+    $this->SubmitButton(TRUE);
+    $this->drupalPost(NULL, array(), t('Add a line item'));
+    $this->LineItemElements(1);
+    $this->SubmitButton(FALSE);
+  }
+
+  /**
+   * Test an AJAX submission.
+   */
+  function testAJAXSubmission() {
+    $this->drupalPostAJAX('payment_test-form-element-payment-line-item', array(), 'payment-line-item', NULL, array(), array(), 'payment-test-form-payment-line-item');
+    $this->LineItemElements(1);
+    $this->SubmitButton(FALSE);
+  }
+
+  /**
+   * Test default value handling.
+   */
+  function testDefaultValues() {
+    $this->drupalGet('payment_test-form-element-payment-line-item/default-values');
+    foreach (payment_test_default_line_items() as $delta => $line_item) {
+      $properties = array(
+        'amount' => $line_item->amount,
+        'description' => $line_item->description,
+        'name' => $line_item->name,
+        'quantity' => $line_item->quantity,
+        'tax_rate' => $line_item->tax_rate * 100,
+      );
+      foreach ($properties as $property => $value) {
+        $elements = $this->xpath('//input[@id="edit-line-item-container-' . $delta . '-' . drupal_clean_css_identifier($property) . '" and @value="' . $value . '"]');
+        $this->assertTrue(isset($elements[0]), "The element contains the <em>$property</em> value for default line item $delta.");
+      }
+    }
+  }
+
+  /**
+   * Test validation.
+   */
+  function testValidation() {
+    // Test valid values.
+    $this->drupalPost('payment_test-form-element-payment-line-item', $this->PaymentLineItemData, t('Submit'));
+    $this->assertUrl('user', array(), 'Valid values trigger form submission.');
+
+    // Test leaving some elements empty.
+    $values = array(
+      'line_item[container_0][description]' => '',
+    ) + $this->PaymentLineItemData;
+    $this->drupalPost('payment_test-form-element-payment-line-item', $values, t('Submit'));
+    $this->assertRaw(t('%title is required, or leave all fields for this line item empty.', array(
+      '%title' => t('Description'),
+    )), "Partially filling in a line item's element throws a validation error.");
+
+    // Test a non-integer quantity.
+    $values =  array(
+      'line_item[container_0][quantity]' => $this->randomName(2),
+    );
+    $this->drupalPost('payment_test-form-element-payment-line-item', $values, t('Submit'));
+    $this->assertText(t('Quantity should be a positive integer.'), 'A non-integer amount throws a validation error.');
+
+    // Test a non-numeric tax rate.
+    $values =  array(
+      'line_item[container_0][tax_rate]' => $this->randomName(2),
+    );
+    $this->drupalPost('payment_test-form-element-payment-line-item', $values, t('Submit'));
+    $this->assertFieldByXPath('//input[@id="edit-line-item-container-0-tax-rate" and contains(@class, "error")]', NULL, 'A non-numeric tax rate throws a validation error.');
+
+    // Test a negative tax rate.
+    $values =  array(
+      'line_item[container_0][tax_rate]' => '-10',
+    );
+    $this->drupalPost('payment_test-form-element-payment-line-item', $values, t('Submit'));
+    $this->assertFieldByXPath('//input[@id="edit-line-item-container-0-tax-rate" and contains(@class, "error")]', NULL, 'A negative tax rate throws a validation error.');
+
+    // Test a float tax rate that uses a period.
+    $values =  array(
+      'line_item[container_0][tax_rate]' => '19.6',
+    );
+    $this->drupalPost('payment_test-form-element-payment-line-item', $values, t('Submit'));
+    $this->assertFieldByXPath('//input[@id="edit-line-item-container-0-tax-rate" and not(contains(@class, "error"))]', NULL, 'A float tax rate that includes a period is valid.');
+
+    // Test a float tax rate that uses a comma.
+    $values =  array(
+      'line_item[container_0][tax_rate]' => '19,6',
+    );
+    $this->drupalPost('payment_test-form-element-payment-line-item', $values, t('Submit'));
+    $this->assertFieldByXPath('//input[@id="edit-line-item-container-0-tax-rate" and not(contains(@class, "error"))]', NULL, 'A float tax rate that includes a comma is valid.');
+  }
+}
diff --git a/payment/tests/payment_test/tests/PaymentTestPaymentLineItemWebTestCase.test b/payment/tests/payment_test/tests/PaymentTestPaymentLineItemWebTestCase.test
new file mode 100644
index 0000000..ed1fea5
--- /dev/null
+++ b/payment/tests/payment_test/tests/PaymentTestPaymentLineItemWebTestCase.test
@@ -0,0 +1,77 @@
+<?php
+
+/**
+ * @file
+ * Contains class PaymentTestPaymentLineItemWebTestCase.
+ */
+
+/**
+ * Tests line item handling.
+ */
+class PaymentTestPaymentLineItemWebTestCase extends PaymentWebTestCase {
+
+  static function getInfo() {
+    return array(
+      'name' => 'Payment line item handling',
+      'group' => 'Payment',
+    );
+  }
+
+  /**
+   * Overrides parent::setUp().
+   */
+  function setUp(array $modules = array()) {
+    parent::setUp($modules + array('payment_test'));
+  }
+
+  /**
+   * Test line item handling.
+   */
+  function testPaymentLineItemHandling() {
+    $payment = new Payment;
+    $payment->setLineItem(new PaymentLineItem(array(
+      'name' => 'foo',
+      'amount' => 19.11,
+      'tax_rate' => 0.1,
+    )));
+
+    // Test Payment::setLineItem();
+    $this->assertTrue($payment->line_items['foo']->name == 'foo', 'Payment::setLineItem() adds a PaymentLineItem object to Payment::line_items.');
+
+    // Test Payment::unitAmount() without tax.
+    $this->assertTrue($payment->line_items['foo']->unitAmount(FALSE) == 19.11, 'Payment::unitAmount() returns amount excluding tax.');
+
+    // Test Payment::unitAmount() with tax.
+    $this->assertTrue($payment->line_items['foo']->unitAmount(TRUE) == 21.021, 'Payment::unitAmount() returns amount including tax.');
+
+    // Test Payment::totalAmount() without tax.
+    $this->assertTrue($payment->totalAmount(FALSE) == 19.11, 'Payment::totalAmount() returns amount excluding tax.');
+
+    $payment->setLineItem(new PaymentLineItem(array(
+      'name' => 'bar',
+      'amount' => 19.78,
+    )));
+
+    // Test Payment::totalAmount() without passed on amounts.
+    $this->assertTrue($payment->totalAmount(TRUE) == 40.801, 'Payment::totalAmount() adds up Payment::line_items.');
+
+    $payment->setLineItem(new PaymentLineItem(array(
+      'name' => 'beer',
+      'amount' => 47.11,
+    )));
+
+    // Test Payment::totalAmount() with passed on amounts.
+    $line_items = $payment->getLineItems('payment_test');
+    $this->assertTrue($payment->totalAmount(TRUE, $line_items) == 40.801, 'Payment::totalAmount() adds up only passed on line items.');
+
+    // Test payment_line_item_get_specific() and whether
+    // Payment::getLineItems() can get line items that are not exposed
+    // through hook_payment_line_item_info().
+    $line_items = $payment->getLineItems('beer');
+    $this->assertTrue($payment->totalAmount(TRUE, $line_items) == 47.11, 'payment_line_item_get_specific() only returns the requested line item.');
+
+    // Test payment_line_item_get_all().
+    $line_items = $payment->getLineItems('payment_all');
+    $this->assertTrue(count($line_items) == 3, 'payment_line_item_get_all() returns all line items.');
+  }
+}
diff --git a/payment/tests/payment_test/tests/PaymentTestPaymentMenuRouterItemPermissionWebTestCase.test b/payment/tests/payment_test/tests/PaymentTestPaymentMenuRouterItemPermissionWebTestCase.test
new file mode 100644
index 0000000..a24c4ce
--- /dev/null
+++ b/payment/tests/payment_test/tests/PaymentTestPaymentMenuRouterItemPermissionWebTestCase.test
@@ -0,0 +1,62 @@
+<?php
+
+/**
+ * @file
+ * Contains class PaymentTestPaymentMenuRouterItemPermissionWebTestCase.
+ */
+
+/**
+ * Tests payment menu router item access control.
+ */
+class PaymentTestPaymentMenuRouterItemPermissionWebTestCase extends PaymentWebTestCase {
+
+  static function getInfo() {
+    return array(
+      'name' => 'Payment menu router item permissions',
+      'group' => 'Payment',
+      'dependencies' => array('payment', 'paymentmethodbasic', 'xtools'),
+    );
+  }
+
+  /**
+   * Overrides parent::setUp().
+   */
+  function setUp(array $modules = array()) {
+    parent::setUp($modules + array('payment', 'paymentmethodbasic', 'xtools'));
+  }
+
+  function testPaymentMenuRouterItemPermissions() {
+    $payment_method = $this->paymentMethodCreate(2, payment_method_controller_load('PaymentMethodBasicController'));
+    entity_save('payment_method', $payment_method);
+    $payment = $this->paymentCreate(2, $payment_method);
+    entity_save('payment', $payment);
+
+    // Test the global configuration page.
+    $this->XtoolsAssertMenuRouterItemPermission('admin/config/services/payment/global', array('payment.global.administer'));
+
+    // Test the payment view page.
+    $this->XtoolsAssertMenuRouterItemPermission('payment/' . $payment->pid, array('payment.payment.view.any'));
+
+    // Test the payment edit page.
+    $this->XtoolsAssertMenuRouterItemPermission('payment/' . $payment->pid . '/edit', array('payment.payment.update.any'));
+
+    // Test the payment delete page.
+    $this->XtoolsAssertMenuRouterItemPermission('payment/' . $payment->pid . '/delete', array('payment.payment.delete.any'));
+
+    // Test the administrative payment overview page (Views disabled).
+    $this->XtoolsAssertMenuRouterItemPermission('admin/content/payment', array('payment.payment.view.any'), array(), 'Views disabled');
+
+    // Test a user's payment overview page (Views disabled).
+    $this->XtoolsAssertMenuRouterItemPermission('user/2/payment', array('payment.payment.view.own'), array(), 'Views disabled');
+
+    // Enable Views.
+    $this->assertTrue(module_enable(array('views')), 'Enabled modules: <em>views</em>');
+    $this->resetAll();
+
+    // Test the administrative payment overview page (Views enabled).
+    $this->XtoolsAssertMenuRouterItemPermission('admin/content/payment', array('payment.payment.view.any'), array(), 'Views enabled');
+
+    // Test a user's payment overview page (Views enabled).
+    $this->XtoolsAssertMenuRouterItemPermission('user/2/payment', array('payment.payment.view.own'), array(), 'Views enabled');
+  }
+}
diff --git a/payment/tests/payment_test/tests/PaymentTestPaymentMethodEntityPermissionWebTestCase.test b/payment/tests/payment_test/tests/PaymentTestPaymentMethodEntityPermissionWebTestCase.test
new file mode 100644
index 0000000..3312b58
--- /dev/null
+++ b/payment/tests/payment_test/tests/PaymentTestPaymentMethodEntityPermissionWebTestCase.test
@@ -0,0 +1,104 @@
+<?php
+
+/**
+ * @file
+ * Contains class PaymentTestPaymentMethodEntityPermissionWebTestCase.
+ */
+
+/**
+ * Tests payment_method entity permissions.
+ */
+class PaymentTestPaymentMethodEntityPermissionWebTestCase extends PaymentWebTestCase {
+
+  static function getInfo() {
+    return array(
+      'name' => 'Payment method permissions',
+      'group' => 'Payment',
+      'dependencies' => array('payment', 'paymentmethodbasic', 'xtools'),
+    );
+  }
+
+  /**
+   * Overrides parent::setUp().
+   */
+  function setUp(array $modules = array()) {
+    parent::setUp($modules + array('payment', 'paymentmethodbasic', 'xtools'));
+  }
+
+  function testPaymentMethodEntityPermissions() {
+    // Create a new payment method.
+    $this->XtoolsAssertEntityPermission($this->paymentMethodCreate(0, payment_method_controller_load('PaymentMethodBasicController')), 'payment method', 'payment_method_access', 'create', array('payment.payment_method.create.PaymentMethodBasicController'));
+
+    // Update a payment method that belongs to user 1.
+    $this->XtoolsAssertEntityPermission($this->paymentMethodCreate(1, payment_method_controller_load('PaymentMethodBasicController')), 'payment method', 'payment_method_access', 'update', array('payment.payment_method.update.any'));
+
+    // Update a payment method that belongs to user 2.
+    $this->XtoolsAssertEntityPermission($this->paymentMethodCreate(2, payment_method_controller_load('PaymentMethodBasicController')), 'payment method', 'payment_method_access', 'update', array('payment.payment_method.update.own'));
+
+    // Delete a payment method that belongs to user 1.
+    $this->XtoolsAssertEntityPermission($this->paymentMethodCreate(1, payment_method_controller_load('PaymentMethodBasicController')), 'payment method', 'payment_method_access', 'delete', array('payment.payment_method.delete.any'));
+
+    // Delete a payment method that belongs to user 2.
+    $this->XtoolsAssertEntityPermission($this->paymentMethodCreate(2, payment_method_controller_load('PaymentMethodBasicController')), 'payment method', 'payment_method_access', 'delete', array('payment.payment_method.delete.own'));
+
+    // Enable an enabled payment method that belongs to user 1.
+    $payment_method = $this->paymentMethodCreate(1, payment_method_controller_load('PaymentMethodBasicController'));
+    $this->XtoolsAssertEntityPermission($payment_method, 'enabled payment method', 'payment_method_access', 'enable', array('payment.payment_method.update.any'), array(
+      'root' => FALSE,
+      'authenticated_with_permissions' => FALSE,
+    ));
+
+    // Enable an enabled payment method that belongs to user 2.
+    $payment_method = $this->paymentMethodCreate(2, payment_method_controller_load('PaymentMethodBasicController'));
+    $this->XtoolsAssertEntityPermission($payment_method, 'enabled payment method', 'payment_method_access', 'enable', array('payment.payment_method.update.own'), array(
+      'root' => FALSE,
+      'authenticated_with_permissions' => FALSE,
+    ));
+
+    // Enable a disabled payment method that belongs to user 1.
+    $payment_method = $this->paymentMethodCreate(1, payment_method_controller_load('PaymentMethodBasicController'));
+    $payment_method->enabled = FALSE;
+    $this->XtoolsAssertEntityPermission($payment_method, 'disabled payment method', 'payment_method_access', 'enable', array('payment.payment_method.update.any'));
+
+    // Enable a disabled payment method that belongs to user 2.
+    $payment_method = $this->paymentMethodCreate(2, payment_method_controller_load('PaymentMethodBasicController'));
+    $payment_method->enabled = FALSE;
+    $this->XtoolsAssertEntityPermission($payment_method, 'disabled payment method', 'payment_method_access', 'enable', array('payment.payment_method.update.own'));
+
+    // Disable a disabled payment method that belongs to user 1.
+    $payment_method = $this->paymentMethodCreate(1, payment_method_controller_load('PaymentMethodBasicController'));
+    $payment_method->enabled = FALSE;
+    $this->XtoolsAssertEntityPermission($payment_method, 'disabled payment method', 'payment_method_access', 'disable', array('payment.payment_method.update.any'), array(
+      'root' => FALSE,
+      'authenticated_with_permissions' => FALSE,
+    ));
+
+    // Disable a disabled payment method that belongs to user 2.
+    $payment_method = $this->paymentMethodCreate(2, payment_method_controller_load('PaymentMethodBasicController'));
+    $payment_method->enabled = FALSE;
+    $this->XtoolsAssertEntityPermission($payment_method, 'disabled payment method', 'payment_method_access', 'disable', array('payment.payment_method.update.own'), array(
+      'root' => FALSE,
+      'authenticated_with_permissions' => FALSE,
+    ));
+
+    // Disable an enabled payment method that belongs to user 1.
+    $payment_method = $this->paymentMethodCreate(1, payment_method_controller_load('PaymentMethodBasicController'));
+    $this->XtoolsAssertEntityPermission($payment_method, 'disabled payment method', 'payment_method_access', 'disable', array('payment.payment_method.update.any'));
+
+    // Enable am enabled payment method that belongs to user 2.
+    $payment_method = $this->paymentMethodCreate(2, payment_method_controller_load('PaymentMethodBasicController'));
+    $this->XtoolsAssertEntityPermission($payment_method, 'disabled payment method', 'payment_method_access', 'disable', array('payment.payment_method.update.own'));
+
+    // Clone a payment method that belongs to user 1.
+    $this->XtoolsAssertEntityPermission($this->paymentMethodCreate(1, payment_method_controller_load('PaymentMethodBasicController')), 'payment method', 'payment_method_access', 'clone', array('payment.payment_method.view.any', 'payment.payment_method.create.PaymentMethodBasicController'));
+
+    // Clone a payment method that belongs to user 2.
+    $this->XtoolsAssertEntityPermission($this->paymentMethodCreate(2, payment_method_controller_load('PaymentMethodBasicController')), 'payment method', 'payment_method_access', 'clone', array('payment.payment_method.view.own', 'payment.payment_method.create.PaymentMethodBasicController'));
+
+    // View a payment method that belongs to user 1.
+    $this->XtoolsAssertEntityPermission($this->paymentMethodCreate(1, payment_method_controller_load('PaymentMethodBasicController')), 'payment method', 'payment_method_access', 'view', array('payment.payment_method.view.any'));
+
+    // View a payment method that belongs to user 2.
+    $this->XtoolsAssertEntityPermission($this->paymentMethodCreate(2, payment_method_controller_load('PaymentMethodBasicController')), 'payment method', 'payment_method_access', 'view', array('payment.payment_method.view.own'));
+  }
+}
diff --git a/payment/tests/payment_test/tests/PaymentTestPaymentMethodMenuRouterItemPermissionWebTestCase.test b/payment/tests/payment_test/tests/PaymentTestPaymentMethodMenuRouterItemPermissionWebTestCase.test
new file mode 100644
index 0000000..28b1c7d
--- /dev/null
+++ b/payment/tests/payment_test/tests/PaymentTestPaymentMethodMenuRouterItemPermissionWebTestCase.test
@@ -0,0 +1,68 @@
+<?php
+
+/**
+ * @file
+ * Contains class PaymentTestPaymentMethodMenuRouterItemPermissionWebTestCase.
+ */
+
+/**
+ * Tests payment method menu router item access control.
+ */
+class PaymentTestPaymentMethodMenuRouterItemPermissionWebTestCase extends PaymentWebTestCase {
+
+  static function getInfo() {
+    return array(
+      'name' => 'Payment method menu router item permissions',
+      'group' => 'Payment',
+      'dependencies' => array('payment', 'paymentmethodbasic', 'xtools'),
+    );
+  }
+
+  /**
+   * Overrides parent::setUp().
+   */
+  function setUp(array $modules = array()) {
+    parent::setUp($modules + array('payment', 'paymentmethodbasic', 'xtools'));
+  }
+
+  function testPaymentMethodMenuRouterItemPermissions() {
+    $payment_method_1 = $this->paymentMethodCreate(1, payment_method_controller_load('PaymentMethodBasicController'));
+    entity_save('payment_method', $payment_method_1);
+    $payment_method_2 = $this->paymentMethodCreate(2, payment_method_controller_load('PaymentMethodBasicController'));
+    entity_save('payment_method', $payment_method_2);
+
+    // Test the payment method overview (Views disabled).
+    $this->XtoolsAssertMenuRouterItemPermission('admin/config/services/payment/method', array('payment.payment_method.view.any'), array(), 'Views disabled');
+
+    // Enable Views.
+    $this->assertTrue(module_enable(array('views')), 'Enabled modules: <em>views</em>');
+    $this->resetAll();
+
+    // Test the payment method overview (Views enabled).
+    $this->XtoolsAssertMenuRouterItemPermission('admin/config/services/payment/method', array('payment.payment_method.view.any'), array(), 'Views enabled');
+
+    // Test the payment method controller selection page.
+    $this->XtoolsAssertMenuRouterItemPermission('admin/config/services/payment/method/add', array('payment.payment_method.create.PaymentMethodBasicController'));
+
+    // Test the payment method add page.
+    $this->XtoolsAssertMenuRouterItemPermission('admin/config/services/payment/method/add/PaymentMethodBasicController', array('payment.payment_method.create.PaymentMethodBasicController'));
+
+    // Test the payment method edit page for a payment method that belongs to user 1.
+    $this->XtoolsAssertMenuRouterItemPermission('admin/config/services/payment/method/' . $payment_method_1->pmid . '/edit', array('payment.payment_method.update.any'));
+
+    // Test the payment method edit page for a payment method that belongs to user 2.
+    $this->XtoolsAssertMenuRouterItemPermission('admin/config/services/payment/method/' . $payment_method_2->pmid . '/edit', array('payment.payment_method.update.own'));
+
+    // Test the payment method delete page for a payment method that belongs to user 1.
+    $this->XtoolsAssertMenuRouterItemPermission('admin/config/services/payment/method/' . $payment_method_1->pmid . '/delete', array('payment.payment_method.delete.any'));
+
+    // Test the payment method delete page for a payment method that belongs to user 2.
+    $this->XtoolsAssertMenuRouterItemPermission('admin/config/services/payment/method/' . $payment_method_2->pmid . '/delete', array('payment.payment_method.delete.own'));
+
+    // Test the payment method clone page for a payment method that belongs to user 1.
+    $this->XtoolsAssertMenuRouterItemPermission('admin/config/services/payment/method/' . $payment_method_1->pmid . '/clone', array('payment.payment_method.view.any', 'payment.payment_method.create.' . $payment_method_1->controller->name));
+
+    // Test the payment method clone page for a payment method that belongs to user 2.
+    $this->XtoolsAssertMenuRouterItemPermission('admin/config/services/payment/method/' . $payment_method_2->pmid . '/clone', array('payment.payment_method.view.own', 'payment.payment_method.create.' . $payment_method_2->controller->name));
+  }
+}
diff --git a/payment/tests/payment_test/tests/PaymentTestPaymentStatusItemWebTestCase.test b/payment/tests/payment_test/tests/PaymentTestPaymentStatusItemWebTestCase.test
new file mode 100644
index 0000000..c0a0ba3
--- /dev/null
+++ b/payment/tests/payment_test/tests/PaymentTestPaymentStatusItemWebTestCase.test
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * @file
+ * Contains class PaymentTestPaymentStatusItemWebTestCase.
+ */
+
+/**
+ * Test payment status item handling.
+ */
+class PaymentTestPaymentStatusItemWebTestCase extends PaymentWebTestCase {
+
+  static function getInfo() {
+    return array(
+      'name' => 'Payment status item handling',
+      'group' => 'Payment',
+    );
+  }
+
+  /**
+   * Overrides parent::setUp().
+   */
+  function setUp(array $modules = array()) {
+    parent::setUp($modules = array('payment'));
+  }
+
+  /**
+   * Test payment status item handling.
+   */
+  function testPaymentStatusItem() {
+    $payment = new Payment;
+    $status_pending = new PaymentStatusItem(PAYMENT_STATUS_PENDING);
+    $status_success = new PaymentStatusItem(PAYMENT_STATUS_SUCCESS);
+    $payment->setStatus($status_pending);
+    $payment->setStatus($status_success);
+    $this->assertTrue($payment->getStatus() === $status_success, 'Payment::setStatus() sets status items in the right order and Payment::getStatus() retrieves them.');
+  }
+}
diff --git a/payment/tests/payment_test/tests/PaymentTestPaymentValidationWebTestCase.test b/payment/tests/payment_test/tests/PaymentTestPaymentValidationWebTestCase.test
new file mode 100644
index 0000000..2eed5b1
--- /dev/null
+++ b/payment/tests/payment_test/tests/PaymentTestPaymentValidationWebTestCase.test
@@ -0,0 +1,155 @@
+<?php
+
+/**
+ * @file
+ * Contains class PaymentTestPaymentValidationWebTestCase.
+ */
+
+/**
+ * Tests payment validation.
+ */
+class PaymentTestPaymentValidationWebTestCase extends PaymentWebTestCase {
+
+  static function getInfo() {
+    return array(
+      'name' => 'Payment validation',
+      'group' => 'Payment',
+    );
+  }
+
+  /**
+   * Overrides parent::setUp().
+   */
+  function setUp(array $modules = array()) {
+    parent::setUp($modules = array('payment', 'paymentmethodbasic', 'payment_test'));
+
+    $this->payment_method = new PaymentMethod(array(
+      'controller' => payment_method_controller_load('PaymentMethodBasicController'),
+    ));
+    $this->payment_method->controller->currencies = array(
+      'XXX' => array(
+        'minimum' => 0.5,
+        'maximum' => 20,
+      ),
+    );
+  }
+
+  /**
+   * Test payment validation.
+   */
+  function testPaymentValidation() {
+    // Test that a valid payment validates.
+    try {
+      $this->payment_method->validate($this->paymentCreate(1, $this->payment_method));
+      $valid = TRUE;
+    }
+    catch (PaymentValidationException $e) {
+      $valid = FALSE;
+    }
+    $this->assertTrue($valid, 'PaymentMethodController::validate() does not invalidate a valid payment.');
+
+    // Test that a payment with a disabled payment method invalidates.
+    try {
+      $this->payment_method->enabled = FALSE;
+      $payment = $this->paymentCreate(1, $this->payment_method);
+      $this->payment_method->validate($payment);
+      $valid = TRUE;
+    }
+    catch (PaymentValidationPaymentMethodDisabledException $e) {
+      $this->payment_method->enabled = TRUE;
+      $valid = FALSE;
+    }
+    $this->assertFalse($valid, 'PaymentMethodController::validate() invalidates a payment of which the payment method is disabled.');
+
+    // Test that a payment without a currency code set invalidates.
+    try {
+      $payment = $this->paymentCreate(1, $this->payment_method);
+      $payment->currency_code = '';
+      $this->payment_method->validate($payment);
+      $valid = TRUE;
+    }
+    catch (PaymentValidationMissingCurrencyException $e) {
+      $valid = FALSE;
+    }
+    $this->assertFalse($valid, 'PaymentMethodController::validate() invalidates a payment that has no currency set.');
+
+    // Test that a payment without a description invalidates.
+    try {
+      $payment = $this->paymentCreate(1, $this->payment_method);
+      unset($payment->description);
+      $this->payment_method->validate($payment);
+      $valid = TRUE;
+    }
+    catch (PaymentValidationDescriptionMissing $e) {
+      $valid = FALSE;
+    }
+    $this->assertFalse($valid, 'PaymentMethodController::validate() invalidates a payment that has no description.');
+
+    // Test that a payment without a description invalidates.
+    try {
+      $payment = $this->paymentCreate(1, $this->payment_method);
+      $payment->description = str_repeat('a', 300);
+      $this->payment_method->validate($payment);
+      $valid = TRUE;
+    }
+    catch (PaymentValidationDescriptionTooLong $e) {
+      $valid = FALSE;
+    }
+    $this->assertFalse($valid, 'PaymentMethodController::validate() invalidates a payment of which the description is too long.');
+
+    // Test that a payment without a (callable) finish callback set
+    // invalidates.
+    try {
+      $payment = $this->paymentCreate(1, $this->payment_method);
+      $payment->finish_callback = '';
+      $this->payment_method->validate($payment);
+      $valid = TRUE;
+    }
+    catch (PaymentValidationMissingFinishCallback $e) {
+      $valid = FALSE;
+    }
+    $this->assertFalse($valid, 'PaymentMethodController::validate() invalidates a payment that has no (callable) finish callback set.');
+
+    // Test that a payment with a total amount below PAYMENT_MINIMUM_AMOUNT
+    // invalidates.
+    try {
+      $payment = $this->paymentCreate(1, $this->payment_method);
+      $payment->line_items = array();
+      $this->payment_method->validate($payment);
+      $valid = TRUE;
+    }
+    catch (PaymentValidationAmountBelowMinimumException $e) {
+      $valid = FALSE;
+    }
+    $this->assertFalse($valid, 'PaymentMethodController::validate() invalidates a payment of which the amount is below the default minimum of ' . PAYMENT_MINIMUM_AMOUNT . '.');
+
+    // Test that a payment with a total amount below its controller's minimum
+    // invalidates.
+    try {
+      $payment = $this->paymentCreate(1, $this->payment_method);
+      $payment->line_items['foo']->amount = 0.1;
+      $this->payment_method->validate($payment);
+      $valid = TRUE;
+    }
+    catch (PaymentValidationAmountBelowMinimumException $e) {
+      $valid = FALSE;
+    }
+    $this->assertFalse($valid, "PaymentMethodController::validate() invalidates a payment of which the amount is below its controller's supported minimum.");
+
+    // Test that a payment with a total amount above its controller's maximum
+    // invalidates.
+    try {
+      $payment = $this->paymentCreate(1, $this->payment_method);
+      $payment->setLineItem(new PaymentLineItem(array(
+        'name' => 'payment_test2',
+        'amount' => 25,
+      )));
+      $this->payment_method->validate($payment);
+      $valid = TRUE;
+    }
+    catch (PaymentValidationAmountExceedsMaximumException $e) {
+      $valid = FALSE;
+    }
+    $this->assertFalse($valid, "PaymentMethodController::validate() invalidates a payment of which the amount exceeds its controller's supported maximum.");
+  }
+}
diff --git a/payment/tests/payment_test/tests/PaymentTestUnavailableWebTestCase.test b/payment/tests/payment_test/tests/PaymentTestUnavailableWebTestCase.test
new file mode 100644
index 0000000..1ff01ea
--- /dev/null
+++ b/payment/tests/payment_test/tests/PaymentTestUnavailableWebTestCase.test
@@ -0,0 +1,49 @@
+<?php
+
+/**
+ * @file
+ * Contains class PaymentTestUnavailableWebTestCase.
+ */
+
+/**
+ * Test unavailable payment methods and payment methods controllers.
+ */
+class PaymentTestUnavailableWebTestCase extends PaymentWebTestCase {
+
+  static function getInfo() {
+    return array(
+      'name' => 'Unavailable payment methods and payment method controllers',
+      'group' => 'Payment',
+    );
+  }
+
+  /**
+   * Overrides parent::setUp().
+   */
+  function setUp(array $modules = array()) {
+    parent::setUp($modules = array('payment', 'paymentmethodbasic'));
+  }
+
+  /**
+   * Test unavailable payment methods and payment method controllers.
+   */
+  function testUnavailable() {
+    // Set a non-existing controller;
+    $controller = payment_method_controller_load('PaymentMethodBasicController');
+    $payment_method = $this->paymentMethodCreate(1, $controller);
+    entity_save('payment_method', $payment_method);
+
+    // Test disabling a module that provides a payment method controller.
+    module_disable(array('paymentmethodbasic'));
+    drupal_static_reset();
+    $payment = $this->paymentCreate(1, $payment_method);
+    entity_save('payment', $payment);
+    $payment = entity_load_single('payment', $payment->pid);
+    $this->assertEqual($payment->method->controller->name, 'PaymentMethodControllerUnavailable', 'When loading a payment method, if its controller unavailable, it is replaced by PaymentMethodControllerUnavailable.');
+
+    // Test deleting a payment method.
+    entity_delete('payment_method', $payment->method->pmid);
+    $payment = entity_load_single('payment', $payment->pid);
+    $this->assertTrue(is_a($payment->method, 'PaymentMethodUnavailable'), 'When loading a payment, if its payment method is unavailable, it is replaced by PaymentMethodUnavailable.');
+  }
+}
diff --git a/payment/tests/payment_test/tests/PaymentTestUpdatePathWebTestCaseWithContent.test b/payment/tests/payment_test/tests/PaymentTestUpdatePathWebTestCaseWithContent.test
deleted file mode 100644
index 0efe6ac..0000000
--- a/payment/tests/payment_test/tests/PaymentTestUpdatePathWebTestCaseWithContent.test
+++ /dev/null
@@ -1,42 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains class PaymentTestUpgradePathWebTestCase.
- */
-
-/**
- * Test Payment's update path.
- */
-class PaymentTestUpdatePathWebTestCase extends UpdatePathTestCase {
-
-  static function getInfo() {
-    return array(
-      'name'  => 'Update path (with existing content and configuration)',
-      'group' => 'Payment',
-      'dependencies' => array('payment', 'paymentform', 'paymentmethodbasic', 'paymentreference'),
-    );
-  }
-
-  function setUp() {
-    $this->profile = 'testing';
-    $this->databaseDumpFiles = array(
-      drupal_get_path('module', 'payment') . '/../payment-database-dump.php',
-      drupal_get_path('module', 'payment') . '/../payment-database-dump-content.php',
-    );
-    parent::setUp();
-    // Re-register the autoload functions that were unregistered by
-    // UpdatePathTestCase::setUp(), because it also loads some module files
-    // that work with classes.
-    spl_autoload_register('drupal_autoload_class');
-    spl_autoload_register('drupal_autoload_interface');
-    registry_rebuild();
-  }
-
-  /**
-   * Test a successful upgrade.
-   */
-  function testPaymentUpgrade() {
-    $this->assertTrue($this->performUpgrade(), 'The update was completed successfully.');
-  }
-}
\ No newline at end of file
diff --git a/payment/tests/payment_test/tests/PaymentTestUpdatePathWebTestCaseWithoutContent.test b/payment/tests/payment_test/tests/PaymentTestUpdatePathWebTestCaseWithoutContent.test
deleted file mode 100644
index fb6e6ab..0000000
--- a/payment/tests/payment_test/tests/PaymentTestUpdatePathWebTestCaseWithoutContent.test
+++ /dev/null
@@ -1,39 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains class PaymentTestUpdatePathWebTestCaseWithoutContent.
- */
-
-/**
- * Test Payment's update path.
- */
-class PaymentTestUpdatePathWebTestCaseWithoutContent extends UpdatePathTestCase {
-
-  static function getInfo() {
-    return array(
-      'name'  => 'Update path (without existing content and configuration)',
-      'group' => 'Payment',
-      'dependencies' => array('payment', 'paymentform', 'paymentmethodbasic', 'paymentreference'),
-    );
-  }
-
-  function setUp() {
-    $this->profile = 'testing';
-    $this->databaseDumpFiles = array(drupal_get_path('module', 'payment') . '/../payment-database-dump.php');
-    parent::setUp();
-    // Re-register the autoload functions that were unregistered by
-    // UpdatePathTestCase::setUp(), because it also loads some module files
-    // that work with classes.
-    spl_autoload_register('drupal_autoload_class');
-    spl_autoload_register('drupal_autoload_interface');
-    registry_rebuild();
-  }
-
-  /**
-   * Test a successful upgrade.
-   */
-  function testPaymentUpgrade() {
-    $this->assertTrue($this->performUpgrade(), 'The update was completed successfully.');
-  }
-}
\ No newline at end of file
diff --git a/payment/tests/payment_test/tests/PaymentTestUpdatePathWithContentWebTestCase.test b/payment/tests/payment_test/tests/PaymentTestUpdatePathWithContentWebTestCase.test
new file mode 100644
index 0000000..af3da5a
--- /dev/null
+++ b/payment/tests/payment_test/tests/PaymentTestUpdatePathWithContentWebTestCase.test
@@ -0,0 +1,45 @@
+<?php
+
+/**
+ * @file
+ * Contains class PaymentTestUpdatePathWithContentWebTestCase.
+ */
+
+/**
+ * Tests Payment's update path.
+ */
+class PaymentTestUpdatePathWithContentWebTestCase extends UpdatePathTestCase {
+
+  static function getInfo() {
+    return array(
+      'name'  => 'Update path (with existing content and configuration)',
+      'group' => 'Payment',
+      'dependencies' => array('payment', 'paymentform', 'paymentmethodbasic', 'paymentreference'),
+    );
+  }
+
+  /**
+   * Overrides parent::setUp().
+   */
+  function setUp() {
+    $this->profile = 'testing';
+    $this->databaseDumpFiles = array(
+      drupal_get_path('module', 'payment') . '/../payment-database-dump.php',
+      drupal_get_path('module', 'payment') . '/../payment-database-dump-content.php',
+    );
+    parent::setUp();
+    // Re-register the autoload functions that were unregistered by
+    // UpdatePathTestCase::setUp(), because it also loads some module files
+    // that work with classes.
+    spl_autoload_register('drupal_autoload_class');
+    spl_autoload_register('drupal_autoload_interface');
+    registry_rebuild();
+  }
+
+  /**
+   * Test a successful upgrade.
+   */
+  function testPaymentUpgrade() {
+    $this->assertTrue($this->performUpgrade(), 'The update was completed successfully.');
+  }
+}
diff --git a/payment/tests/payment_test/tests/PaymentTestUpdatePathWithoutContentWebTestCase.test b/payment/tests/payment_test/tests/PaymentTestUpdatePathWithoutContentWebTestCase.test
new file mode 100644
index 0000000..6b58fbb
--- /dev/null
+++ b/payment/tests/payment_test/tests/PaymentTestUpdatePathWithoutContentWebTestCase.test
@@ -0,0 +1,42 @@
+<?php
+
+/**
+ * @file
+ * Contains class PaymentTestUpdatePathWithoutContentWebTestCase.
+ */
+
+/**
+ * Tests Payment's update path.
+ */
+class PaymentTestUpdatePathWithoutContentWebTestCase extends UpdatePathTestCase {
+
+  static function getInfo() {
+    return array(
+      'name'  => 'Update path (without existing content and configuration)',
+      'group' => 'Payment',
+      'dependencies' => array('payment', 'paymentform', 'paymentmethodbasic', 'paymentreference'),
+    );
+  }
+
+  /**
+   * Overrides parent::setUp().
+   */
+  function setUp() {
+    $this->profile = 'testing';
+    $this->databaseDumpFiles = array(drupal_get_path('module', 'payment') . '/../payment-database-dump.php');
+    parent::setUp();
+    // Re-register the autoload functions that were unregistered by
+    // UpdatePathTestCase::setUp(), because it also loads some module files
+    // that work with classes.
+    spl_autoload_register('drupal_autoload_class');
+    spl_autoload_register('drupal_autoload_interface');
+    registry_rebuild();
+  }
+
+  /**
+   * Test a successful upgrade.
+   */
+  function testPaymentUpgrade() {
+    $this->assertTrue($this->performUpgrade(), 'The update was completed successfully.');
+  }
+}
diff --git a/payment/tests/payment_test/tests/PaymentUnavailableWebTestCase.test b/payment/tests/payment_test/tests/PaymentUnavailableWebTestCase.test
deleted file mode 100644
index 7c19b82..0000000
--- a/payment/tests/payment_test/tests/PaymentUnavailableWebTestCase.test
+++ /dev/null
@@ -1,41 +0,0 @@
-<?php
-
-/**
- * Test unavailable payment methods and payment methods controllers.
- */
-class PaymentUnavailableWebTestCase extends PaymentWebTestCase {
-
-  static function getInfo() {
-    return array(
-      'name' => 'Unavailable payment methods and payment method controllers',
-      'group' => 'Payment',
-    );
-  }
-
-  function setUp(array $modules = array()) {
-    parent::setUp($modules = array('payment', 'paymentmethodbasic'));
-  }
-
-  /**
-   * Test unavailable payment methods and payment method controllers.
-   */
-  function testUnavailable() {
-    // Set a non-existing controller;
-    $controller = payment_method_controller_load('PaymentMethodBasicController');
-    $payment_method = $this->paymentMethodCreate(1, $controller);
-    entity_save('payment_method', $payment_method);
-
-    // Test disabling a module that provides a payment method controller.
-    module_disable(array('paymentmethodbasic'));
-    drupal_static_reset();
-    $payment = $this->paymentCreate(1, $payment_method);
-    entity_save('payment', $payment);
-    $payment = entity_load_single('payment', $payment->pid);
-    $this->assertEqual($payment->method->controller->name, 'PaymentMethodControllerUnavailable', 'When loading a payment method, if its controller unavailable, it is replaced by PaymentMethodControllerUnavailable.');
-
-    // Test deleting a payment method.
-    entity_delete('payment_method', $payment->method->pmid);
-    $payment = entity_load_single('payment', $payment->pid);
-    $this->assertTrue(is_a($payment->method, 'PaymentMethodUnavailable'), 'When loading a payment, if its payment method is unavailable, it is replaced by PaymentMethodUnavailable.');
-  }
-}
\ No newline at end of file
diff --git a/payment/tests/payment_test/tests/PaymentValidationWebTestCase.test b/payment/tests/payment_test/tests/PaymentValidationWebTestCase.test
deleted file mode 100644
index b805fbc..0000000
--- a/payment/tests/payment_test/tests/PaymentValidationWebTestCase.test
+++ /dev/null
@@ -1,150 +0,0 @@
-<?php
-
-/**
- * Test payment validation.
- */
-class PaymentValidationWebTestCase extends PaymentWebTestCase {
-
-  static function getInfo() {
-    return array(
-      'name' => 'Payment validation',
-      'group' => 'Payment',
-    );
-  }
-
-  /**
-   * Implements DrupalWebTestCase::setUp().
-   */
-  function setUp(array $modules = array()) {
-    parent::setUp($modules = array('payment', 'paymentmethodbasic', 'payment_test'));
-
-    $this->payment_method = new PaymentMethod(array(
-      'controller' => payment_method_controller_load('PaymentMethodBasicController'),
-    ));
-    $this->payment_method->controller->currencies = array(
-      'XXX' => array(
-        'minimum' => 0.5,
-        'maximum' => 20,
-      ),
-    );
-  }
-
-  /**
-   * Test payment validation.
-   */
-  function testPaymentValidation() {
-    // Test that a valid payment validates.
-    try {
-      $this->payment_method->validate($this->paymentCreate(1, $this->payment_method));
-      $valid = TRUE;
-    }
-    catch (PaymentValidationException $e) {
-      $valid = FALSE;
-    }
-    $this->assertTrue($valid, 'PaymentMethodController::validate() does not invalidate a valid payment.');
-
-    // Test that a payment with a disabled payment method invalidates.
-    try {
-      $this->payment_method->enabled = FALSE;
-      $payment = $this->paymentCreate(1, $this->payment_method);
-      $this->payment_method->validate($payment);
-      $valid = TRUE;
-    }
-    catch (PaymentValidationPaymentMethodDisabledException $e) {
-      $this->payment_method->enabled = TRUE;
-      $valid = FALSE;
-    }
-    $this->assertFalse($valid, 'PaymentMethodController::validate() invalidates a payment of which the payment method is disabled.');
-
-    // Test that a payment without a currency code set invalidates.
-    try {
-      $payment = $this->paymentCreate(1, $this->payment_method);
-      $payment->currency_code = '';
-      $this->payment_method->validate($payment);
-      $valid = TRUE;
-    }
-    catch (PaymentValidationMissingCurrencyException $e) {
-      $valid = FALSE;
-    }
-    $this->assertFalse($valid, 'PaymentMethodController::validate() invalidates a payment that has no currency set.');
-
-    // Test that a payment without a description invalidates.
-    try {
-      $payment = $this->paymentCreate(1, $this->payment_method);
-      unset($payment->description);
-      $this->payment_method->validate($payment);
-      $valid = TRUE;
-    }
-    catch (PaymentValidationDescriptionMissing $e) {
-      $valid = FALSE;
-    }
-    $this->assertFalse($valid, 'PaymentMethodController::validate() invalidates a payment that has no description.');
-
-    // Test that a payment without a description invalidates.
-    try {
-      $payment = $this->paymentCreate(1, $this->payment_method);
-      $payment->description = str_repeat('a', 300);
-      $this->payment_method->validate($payment);
-      $valid = TRUE;
-    }
-    catch (PaymentValidationDescriptionTooLong $e) {
-      $valid = FALSE;
-    }
-    $this->assertFalse($valid, 'PaymentMethodController::validate() invalidates a payment of which the description is too long.');
-
-    // Test that a payment without a (callable) finish callback set
-    // invalidates.
-    try {
-      $payment = $this->paymentCreate(1, $this->payment_method);
-      $payment->finish_callback = '';
-      $this->payment_method->validate($payment);
-      $valid = TRUE;
-    }
-    catch (PaymentValidationMissingFinishCallback $e) {
-      $valid = FALSE;
-    }
-    $this->assertFalse($valid, 'PaymentMethodController::validate() invalidates a payment that has no (callable) finish callback set.');
-
-    // Test that a payment with a total amount below PAYMENT_MINIMUM_AMOUNT
-    // invalidates.
-    try {
-      $payment = $this->paymentCreate(1, $this->payment_method);
-      $payment->line_items = array();
-      $this->payment_method->validate($payment);
-      $valid = TRUE;
-    }
-    catch (PaymentValidationAmountBelowMinimumException $e) {
-      $valid = FALSE;
-    }
-    $this->assertFalse($valid, 'PaymentMethodController::validate() invalidates a payment of which the amount is below the default minimum of ' . PAYMENT_MINIMUM_AMOUNT . '.');
-
-    // Test that a payment with a total amount below its controller's minimum
-    // invalidates.
-    try {
-      $payment = $this->paymentCreate(1, $this->payment_method);
-      $payment->line_items['foo']->amount = 0.1;
-      $this->payment_method->validate($payment);
-      $valid = TRUE;
-    }
-    catch (PaymentValidationAmountBelowMinimumException $e) {
-      $valid = FALSE;
-    }
-    $this->assertFalse($valid, "PaymentMethodController::validate() invalidates a payment of which the amount is below its controller's supported minimum.");
-
-    // Test that a payment with a total amount above its controller's maximum
-    // invalidates.
-    try {
-      $payment = $this->paymentCreate(1, $this->payment_method);
-      $payment->setLineItem(new PaymentLineItem(array(
-        'name' => 'payment_test2',
-        'amount' => 25,
-      )));
-      $this->payment_method->validate($payment);
-      $valid = TRUE;
-    }
-    catch (PaymentValidationAmountExceedsMaximumException $e) {
-      $valid = FALSE;
-    }
-    $this->assertFalse($valid, "PaymentMethodController::validate() invalidates a payment of which the amount exceeds its controller's supported maximum.");
-  }
-}
\ No newline at end of file
diff --git a/payment/tests/payment_test/tests/PaymentWebTestCase.test b/payment/tests/payment_test/tests/PaymentWebTestCase.test
deleted file mode 100644
index f602c5c..0000000
--- a/payment/tests/payment_test/tests/PaymentWebTestCase.test
+++ /dev/null
@@ -1,62 +0,0 @@
-<?php
-
-class PaymentWebTestCase extends XtoolsWebTestCase {
-
-  function setUp(array $modules = array()) {
-    $this->profile = 'testing';
-    parent::setUp($modules);
-  }
-
-  /**
-   * Create, save, and return a Payment.
-   *
-   * @param integer $uid
-   *   The user ID of the payment's owner.
-   * @param PaymentMethod $payment_method
-   *   An optional payment method to set. Defaults to PaymentMethodUnavailable.
-   *
-   * @return Payment
-   */
-  static function paymentCreate($uid, PaymentMethod $payment_method = NULL) {
-    $payment_method = $payment_method ? $payment_method : new PaymentMethodUnavailable;
-    $payment = new Payment(array(
-      'currency_code' => 'XXX',
-      'description' => 'This is the payment description',
-      'finish_callback' => 'payment_test_finish_callback',
-      'method' => $payment_method,
-      'uid' => $uid,
-    ));
-    $payment->setLineItem(new PaymentLineItem(array(
-      'name' => 'foo',
-      'amount' => 1.0,
-      'tax_rate' => 0.1,
-    )));
-
-    return $payment;
-  }
-
-  /**
-   * Create, save, and return a PaymentMethod.
-   *
-   * @param integer $uid
-   *   The user ID of the payment method's owner.
-   * @param PaymentMethodController $controller
-   *   An optional controller to set. Defaults to
-   *   PaymentMethodControllerUnavailable.
-   *
-   * @return PaymentMethod
-   */
-  static function paymentMethodCreate($uid, PaymentMethodController $controller = NULL) {
-    $name = self::randomName();
-    $controller = $controller ? $controller : payment_method_controller_load('PaymentMethodControllerUnavailable');
-    $payment_method = new PaymentMethod(array(
-      'controller' => $controller,
-      'controller_data' => $controller->controller_data_defaults,
-      'name' => $name,
-      'title' => $name,
-      'uid' => $uid,
-    ));
-
-    return $payment_method;
-  }
-}
\ No newline at end of file
diff --git a/paymentform/paymentform.info b/paymentform/paymentform.info
index 5a0081f..c0a8daf 100644
--- a/paymentform/paymentform.info
+++ b/paymentform/paymentform.info
@@ -4,4 +4,5 @@ dependencies[] = currency_api
 dependencies[] = payment
 package = Payment
 core = 7.x
-files[] = tests/paymentform.test
\ No newline at end of file
+files[] = tests/paymentform.test
+files[] = tests/PaymentformWebTestCase.test
diff --git a/paymentform/tests/PaymentformWebTestCase.test b/paymentform/tests/PaymentformWebTestCase.test
new file mode 100644
index 0000000..6c6bb00
--- /dev/null
+++ b/paymentform/tests/PaymentformWebTestCase.test
@@ -0,0 +1,63 @@
+<?php
+
+/**
+ * @file
+ * Contains class PaymentformWebTestCase.
+ */
+
+/**
+ * Contains functionality shared by Paymentform test cases.
+ */
+class PaymentformWebTestCase extends PaymentWebTestCase {
+  /**
+   * Overrides parent::setUp().
+   */
+
+  /**
+   * Overrides parent::setUp().
+   */
+  function setUp(array $modules = array()) {
+    parent::setUp($modules + array('field', 'node', 'paymentform'));
+
+    $this->content_type = $this->drupalCreateContentType();
+    // Field configuration.
+    $this->field_paymentform = field_create_field(array(
+      'field_name' => 'field_paymentform',
+      'type' => 'paymentform',
+      'cardinality' => 2,
+    ));
+    $this->field_paymentform_instance = field_create_instance(array(
+      'field_name' => 'field_paymentform',
+      'entity_type' => 'node',
+      'bundle' => $this->content_type->type,
+      'widget' => array(
+        'type' => 'paymentform_line_item',
+      ),
+    ));
+    $this->PaymentLineItemData = array(
+      'amount' => 1.0,
+      'description' => 'foo',
+      'name' => 'bar',
+      'quantity' => 1,
+      'tax_rate' => 0.0,
+    );
+  }
+
+  /**
+   * Checks if a FieldValidationException contains a specified error code.
+   *
+   * @param FieldValidationException $e
+   * @param string $code
+   *
+   * @return boolean
+   */
+  function fieldValidationExceptionError(FieldValidationException $e, $code) {
+    $codes = array();
+    foreach ($e->errors['field_paymentform'][LANGUAGE_NONE][0] as $error) {
+      if ($error['error'] == $code) {
+        return TRUE;
+      }
+    }
+    return FALSE;
+  }
+}
diff --git a/paymentform/tests/paymentform_test/paymentform_test.info b/paymentform/tests/paymentform_test/paymentform_test.info
index dd5e150..f8e8ee9 100644
--- a/paymentform/tests/paymentform_test/paymentform_test.info
+++ b/paymentform/tests/paymentform_test/paymentform_test.info
@@ -5,7 +5,7 @@ dependencies[] = paymentform
 dependencies[] = xtools
 package = Payment
 hidden = TRUE
-files[] = tests/PaymentformFieldWebTestCase.test
-files[] = tests/PaymentformCallablesWebTestCase.test
-files[] = tests/PaymentformLineItemFieldWidgetWebTestCase.test
-files[] = tests/PaymentformWebTestCase.test
\ No newline at end of file
+files[] = tests/PaymentformTestCallablesWebTestCase.test
+files[] = tests/PaymentformTestFieldWebTestCase.test
+files[] = tests/PaymentformTestFieldFormatterWebTestCase.test
+files[] = tests/PaymentformTestLineItemFieldWidgetWebTestCase.test
diff --git a/paymentform/tests/paymentform_test/tests/PaymentformCallablesWebTestCase.test b/paymentform/tests/paymentform_test/tests/PaymentformCallablesWebTestCase.test
deleted file mode 100644
index 42b4377..0000000
--- a/paymentform/tests/paymentform_test/tests/PaymentformCallablesWebTestCase.test
+++ /dev/null
@@ -1,20 +0,0 @@
-<?php
-
-class PaymentFormCallablesValueWebTestCase extends PaymentWebTestCase {
-
-  static function getInfo() {
-    return array(
-      'name' => "Callables",
-      'group' => 'Payment Form Field',
-      'dependencies' => array('paymentform', 'xtools'),
-    );
-  }
-
-  function setUp(array $modules = array()) {
-    parent::setUp($modules + array('paymentform', 'xtools'));
-  }
-
-  function testCallables() {
-    $this->XtoolsAssertCallables(array('paymentform', 'paymentform_test'), array('drupal'));
-  }
-}
\ No newline at end of file
diff --git a/paymentform/tests/paymentform_test/tests/PaymentformFieldFormatterWebTestCase.test b/paymentform/tests/paymentform_test/tests/PaymentformFieldFormatterWebTestCase.test
deleted file mode 100644
index a41fdce..0000000
--- a/paymentform/tests/paymentform_test/tests/PaymentformFieldFormatterWebTestCase.test
+++ /dev/null
@@ -1,26 +0,0 @@
-<?php
-
-/**
- * Test the paymentform field formatter.
- */
-class PaymentformFieldFormatterWebTestCase extends PaymentformWebTestCase {
-
-  static function getInfo() {
-    return array(
-      'name' => 'Payment form field formatter',
-      'group' => 'Payment Form Field',
-    );
-  }
-
-  /**
-   * Test the paymentform field formatter.
-   */
-  function testPaymentformFieldFormatter() {
-    $node = $this->drupalCreateNode();
-    $node->field_paymentform[LANGUAGE_NONE][0] = $this->PaymentLineItemData;
-    node_save($node);
-    $this->drupalGet('node/' . $node->nid);
-    $elements = $this->xpath('//form[@id="payment-form"]');
-    $this->assertTrue(isset($elements[0]), 'The <em>Payment form</em> field formatter shows a payment form.');
-  }
-}
\ No newline at end of file
diff --git a/paymentform/tests/paymentform_test/tests/PaymentformFieldWebTestCase.test b/paymentform/tests/paymentform_test/tests/PaymentformFieldWebTestCase.test
deleted file mode 100644
index cfc7417..0000000
--- a/paymentform/tests/paymentform_test/tests/PaymentformFieldWebTestCase.test
+++ /dev/null
@@ -1,111 +0,0 @@
-<?php
-
-/**
- * Tests the paymentform field.
- */
-class PaymentformFieldWebTestCase extends PaymentformWebTestCase {
-
-  static function getInfo() {
-    return array(
-      'name' => 'Payment form field',
-      'group' => 'Payment Form Field',
-    );
-  }
-
-  /**
-   * Test the paymentform field validation.
-   */
-  function testPaymentformFieldValidation() {
-    $node = $this->DrupalCreateNode();
-    $line_item_data = array();
-    $node->field_paymentform[LANGUAGE_NONE][0] = &$line_item_data;
-
-    // Test that a non-float amount is invalid.
-    $line_item_data = array(
-      'amount' => 2,
-    ) + $this->PaymentLineItemData;
-    $message = "The <em>Payment form</em> field's validation throws an error if the amount is no float";
-    try {
-      field_attach_validate('node', $node);
-      $this->assertTrue(FALSE, $message);
-    }
-    catch (FieldValidationException $e) {
-      $this->assertTrue($this->fieldValidationExceptionError($e, 'paymentform_line_item_amount_no_float'), $message);
-    }
-
-    // Test the machine name, which cannot be empty.
-    $line_item_data = array(
-      'name' => '',
-    ) + $this->PaymentLineItemData;
-    $message = "The <em>Payment form</em> field's validation throws an error if the machine name is empty";
-    try {
-      field_attach_validate('node', $node);
-      $this->assertTrue(FALSE, $message);
-    }
-    catch (FieldValidationException $e) {
-      $this->assertTrue($this->fieldValidationExceptionError($e, 'paymentform_line_item_name_empty'), $message);
-    }
-
-    // Test that a non-integer quantity is invalid.
-    $line_item_data = array(
-      'quantity' => 1.0,
-    ) + $this->PaymentLineItemData;
-    $message = "The <em>Payment form</em> field's validation throws an error if the quantity amount is no integer";
-    try {
-      field_attach_validate('node', $node);
-      $this->assertTrue(FALSE, $message);
-    }
-    catch (FieldValidationException $e) {
-      $this->assertTrue($this->fieldValidationExceptionError($e, 'paymentform_line_item_quantity_no_integer'), $message);
-    }
-    // Test that a negative quantity is invalid.
-    $line_item_data = array(
-      'quantity' => -1,
-    ) + $this->PaymentLineItemData;
-    $message = "The <em>Payment form</em> field's validation throws an error if the quantity is negative";
-    try {
-      field_attach_validate('node', $node);
-      $this->assertTrue(FALSE, $message);
-    }
-    catch (FieldValidationException $e) {
-      $this->assertTrue($this->fieldValidationExceptionError($e, 'paymentform_line_item_quantity_negative'), $message);
-    }
-
-    // Test that a non-float tax rate is invalid.
-    $line_item_data = array(
-      'tax_rate' => 2,
-    ) + $this->PaymentLineItemData;
-    $message = "The <em>Payment form</em> field's validation throws an error if the tax rate is no float";
-    try {
-      field_attach_validate('node', $node);
-      $this->assertTrue(FALSE, $message);
-    }
-    catch (FieldValidationException $e) {
-      $this->assertTrue($this->fieldValidationExceptionError($e, 'paymentform_line_item_tax_rate_no_float'), $message);
-    }
-    // Test that a negative tax rate is invalid.
-    $line_item_data = array(
-      'tax_rate' => -1.0,
-    ) + $this->PaymentLineItemData;
-    $message = "The <em>Payment form</em> field's validation throws an error if the tax rate is negative";
-    try {
-      field_attach_validate('node', $node);
-      $this->assertTrue(FALSE, $message);
-    }
-    catch (FieldValidationException $e) {
-      $this->assertTrue($this->fieldValidationExceptionError($e, 'paymentform_line_item_tax_rate_negative'), $message);
-    }
-  }
-
-  /**
-   * Test the paymentform field storage.
-   */
-  function testPaymentformFieldStorage() {
-    $node = $this->drupalCreateNode();
-    $node->field_paymentform[LANGUAGE_NONE][0] = $this->PaymentLineItemData;
-    node_save($node);
-    $node = node_load($node->nid, NULL, TRUE);
-    $diff = array_diff_assoc($node->field_paymentform[LANGUAGE_NONE][0], $this->PaymentLineItemData);
-    $this->assertTrue(is_array($diff) && empty($diff), 'Payment line item data is saved and loaded correctly.');
-  }
-}
\ No newline at end of file
diff --git a/paymentform/tests/paymentform_test/tests/PaymentformLineItemFieldWidgetWebTestCase.test b/paymentform/tests/paymentform_test/tests/PaymentformLineItemFieldWidgetWebTestCase.test
deleted file mode 100644
index 0cd2829..0000000
--- a/paymentform/tests/paymentform_test/tests/PaymentformLineItemFieldWidgetWebTestCase.test
+++ /dev/null
@@ -1,29 +0,0 @@
-<?php
-
-/**
- * Tests the paymentform_line_item field widget.
- */
-class PaymentformLineItemFieldWidgetWebTestCase extends PaymentformWebTestCase {
-
-  static function getInfo() {
-    return array(
-      'name' => 'Payment line item field widget',
-      'group' => 'Payment Form Field',
-    );
-  }
-
-  function setUp(array $modules = array()) {
-    parent::setUp($modules);
-    $web_user = $this->drupalCreateUser(array('create page content'));
-    $this->drupalLogin($web_user);
-  }
-
-  /**
-   * Test the widget's presence.
-   */
-  function testPaymentformLineItemFieldWidgetInputElements() {
-    $this->drupalGet('node/add/page');
-    $elements = $this->xpath('//div[@id="edit-field-paymentform-und-line-item-container-0"]');
-    $this->assertTrue(isset($elements[0]), 'The <em>Payment line item configuration</em> field widget shows the <em>payment_line_item</em> form element.');
-  }
-}
\ No newline at end of file
diff --git a/paymentform/tests/paymentform_test/tests/PaymentformTestCallablesWebTestCase.test b/paymentform/tests/paymentform_test/tests/PaymentformTestCallablesWebTestCase.test
new file mode 100644
index 0000000..7faf20b
--- /dev/null
+++ b/paymentform/tests/paymentform_test/tests/PaymentformTestCallablesWebTestCase.test
@@ -0,0 +1,34 @@
+<?php
+
+/**
+ * @file
+ * Contains class PaymentformTestCallablesWebTestCase.
+ */
+
+/**
+ * Tests implementations of callables.
+ */
+class PaymentformTestCallablesWebTestCase extends PaymentWebTestCase {
+
+  static function getInfo() {
+    return array(
+      'name' => 'Hook and callback implementations',
+      'group' => 'Payment Form Field',
+      'dependencies' => array('paymentform', 'xtools'),
+    );
+  }
+  /**
+   * Overrides parent::setUp().
+   */
+
+  /**
+   * Overrides parent::setUp().
+   */
+  function setUp(array $modules = array()) {
+    parent::setUp($modules + array('paymentform', 'xtools'));
+  }
+
+  function testCallables() {
+    $this->XtoolsAssertCallables(array('paymentform', 'paymentform_test'), array('drupal'));
+  }
+}
diff --git a/paymentform/tests/paymentform_test/tests/PaymentformTestFieldFormatterWebTestCase.test b/paymentform/tests/paymentform_test/tests/PaymentformTestFieldFormatterWebTestCase.test
new file mode 100644
index 0000000..9c9272d
--- /dev/null
+++ b/paymentform/tests/paymentform_test/tests/PaymentformTestFieldFormatterWebTestCase.test
@@ -0,0 +1,41 @@
+<?php
+
+/**
+ * @file
+ * Contains class PaymentformTestFieldFormatterWebTestCase.
+ */
+
+/**
+ * Tests the paymentform field formatter.
+ */
+class PaymentformTestFieldFormatterWebTestCase extends PaymentformWebTestCase {
+
+  static function getInfo() {
+    return array(
+      'name' => 'Payment form field formatter',
+      'group' => 'Payment Form Field',
+      'dependencies' => array('paymentform_test'),
+    );
+  }
+
+  /**
+   * Overrides parent::setUp().
+   */
+  function setUp(array $modules = array()) {
+    parent::setUp($modules + array('paymentform_test'));
+  }
+
+  /**
+   * Test the paymentform field formatter.
+   */
+  function testPaymentformFieldFormatter() {
+    $node = $this->drupalCreateNode(array(
+      'type' => $this->content_type->type,
+    ));
+    $node->field_paymentform[LANGUAGE_NONE][0] = $this->PaymentLineItemData;
+    node_save($node);
+    $this->drupalGet('node/' . $node->nid);
+    $elements = $this->xpath('//form[@id="payment-form-standalone"]');
+    $this->assertTrue(isset($elements[0]), 'The <em>Payment form</em> field formatter shows a payment form.');
+  }
+}
diff --git a/paymentform/tests/paymentform_test/tests/PaymentformTestFieldWebTestCase.test b/paymentform/tests/paymentform_test/tests/PaymentformTestFieldWebTestCase.test
new file mode 100644
index 0000000..9f59dfd
--- /dev/null
+++ b/paymentform/tests/paymentform_test/tests/PaymentformTestFieldWebTestCase.test
@@ -0,0 +1,120 @@
+<?php
+
+/**
+ * @file
+ * Contains class PaymentformTestFieldWebTestCase.
+ */
+
+/**
+ * Tests the paymentform field.
+ */
+class PaymentformTestFieldWebTestCase extends PaymentformWebTestCase {
+
+  static function getInfo() {
+    return array(
+      'name' => 'Payment form field',
+      'group' => 'Payment Form Field',
+    );
+  }
+
+  /**
+   * Test the paymentform field validation.
+   */
+  function testPaymentformFieldValidation() {
+    $node = $this->DrupalCreateNode(array(
+      'type' => $this->content_type->type,
+    ));
+    $line_item_data = array();
+    $node->field_paymentform[LANGUAGE_NONE][0] = &$line_item_data;
+
+    // Test that a non-float amount is invalid.
+    $line_item_data = array(
+      'amount' => 2,
+    ) + $this->PaymentLineItemData;
+    $message = "The <em>Payment form</em> field's validation throws an error if the amount is no float";
+    try {
+      field_attach_validate('node', $node);
+      $this->assertTrue(FALSE, $message);
+    }
+    catch (FieldValidationException $e) {
+      $this->assertTrue($this->fieldValidationExceptionError($e, 'paymentform_line_item_amount_no_float'), $message);
+    }
+
+    // Test the machine name, which cannot be empty.
+    $line_item_data = array(
+      'name' => '',
+    ) + $this->PaymentLineItemData;
+    $message = "The <em>Payment form</em> field's validation throws an error if the machine name is empty";
+    try {
+      field_attach_validate('node', $node);
+      $this->assertTrue(FALSE, $message);
+    }
+    catch (FieldValidationException $e) {
+      $this->assertTrue($this->fieldValidationExceptionError($e, 'paymentform_line_item_name_empty'), $message);
+    }
+
+    // Test that a non-integer quantity is invalid.
+    $line_item_data = array(
+      'quantity' => 1.0,
+    ) + $this->PaymentLineItemData;
+    $message = "The <em>Payment form</em> field's validation throws an error if the quantity amount is no integer";
+    try {
+      field_attach_validate('node', $node);
+      $this->assertTrue(FALSE, $message);
+    }
+    catch (FieldValidationException $e) {
+      $this->assertTrue($this->fieldValidationExceptionError($e, 'paymentform_line_item_quantity_no_integer'), $message);
+    }
+    // Test that a negative quantity is invalid.
+    $line_item_data = array(
+      'quantity' => -1,
+    ) + $this->PaymentLineItemData;
+    $message = "The <em>Payment form</em> field's validation throws an error if the quantity is negative";
+    try {
+      field_attach_validate('node', $node);
+      $this->assertTrue(FALSE, $message);
+    }
+    catch (FieldValidationException $e) {
+      $this->assertTrue($this->fieldValidationExceptionError($e, 'paymentform_line_item_quantity_negative'), $message);
+    }
+
+    // Test that a non-float tax rate is invalid.
+    $line_item_data = array(
+      'tax_rate' => 2,
+    ) + $this->PaymentLineItemData;
+    $message = "The <em>Payment form</em> field's validation throws an error if the tax rate is no float";
+    try {
+      field_attach_validate('node', $node);
+      $this->assertTrue(FALSE, $message);
+    }
+    catch (FieldValidationException $e) {
+      $this->assertTrue($this->fieldValidationExceptionError($e, 'paymentform_line_item_tax_rate_no_float'), $message);
+    }
+    // Test that a negative tax rate is invalid.
+    $line_item_data = array(
+      'tax_rate' => -1.0,
+    ) + $this->PaymentLineItemData;
+    $message = "The <em>Payment form</em> field's validation throws an error if the tax rate is negative";
+    try {
+      field_attach_validate('node', $node);
+      $this->assertTrue(FALSE, $message);
+    }
+    catch (FieldValidationException $e) {
+      $this->assertTrue($this->fieldValidationExceptionError($e, 'paymentform_line_item_tax_rate_negative'), $message);
+    }
+  }
+
+  /**
+   * Test the paymentform field storage.
+   */
+  function testPaymentformFieldStorage() {
+    $node = $this->drupalCreateNode(array(
+      'type' => $this->content_type->type,
+    ));
+    $node->field_paymentform[LANGUAGE_NONE][0] = $this->PaymentLineItemData;
+    node_save($node);
+    $node = node_load($node->nid, NULL, TRUE);
+    $diff = array_diff_assoc($node->field_paymentform[LANGUAGE_NONE][0], $this->PaymentLineItemData);
+    $this->assertTrue(is_array($diff) && empty($diff), 'Payment line item data is saved and loaded correctly.');
+  }
+}
diff --git a/paymentform/tests/paymentform_test/tests/PaymentformTestLineItemFieldWidgetWebTestCase.test b/paymentform/tests/paymentform_test/tests/PaymentformTestLineItemFieldWidgetWebTestCase.test
new file mode 100644
index 0000000..23e7163
--- /dev/null
+++ b/paymentform/tests/paymentform_test/tests/PaymentformTestLineItemFieldWidgetWebTestCase.test
@@ -0,0 +1,40 @@
+<?php
+
+/**
+ * Contains class PaymentformTestLineItemFieldWidgetWebTestCase.
+ */
+
+/**
+ * Tests the paymentform_line_item field widget.
+ */
+class PaymentformTestLineItemFieldWidgetWebTestCase extends PaymentformWebTestCase {
+
+  static function getInfo() {
+    return array(
+      'name' => 'Payment line item field widget',
+      'group' => 'Payment Form Field',
+      'dependencies' => array('node'),
+    );
+  }
+  /**
+   * Overrides parent::setUp().
+   */
+
+  /**
+   * Overrides parent::setUp().
+   */
+  function setUp(array $modules = array()) {
+    parent::setUp($modules + array('paymentform_test'));
+  }
+
+  /**
+   * Test the widget's presence.
+   */
+  function testPaymentformLineItemFieldWidgetInputElements() {
+    $web_user = $this->drupalCreateUser(array('create ' . $this->content_type->type . ' content'));
+    $this->drupalLogin($web_user);
+    $this->drupalGet('node/add/page');
+    $elements = $this->xpath('//div[@id="edit-field-paymentform-und-line-item-container-0"]');
+    $this->assertTrue(isset($elements[0]), 'The <em>Payment line item configuration</em> field widget shows the <em>payment_line_item</em> form element.');
+  }
+}
diff --git a/paymentform/tests/paymentform_test/tests/PaymentformWebTestCase.test b/paymentform/tests/paymentform_test/tests/PaymentformWebTestCase.test
deleted file mode 100644
index 068dada..0000000
--- a/paymentform/tests/paymentform_test/tests/PaymentformWebTestCase.test
+++ /dev/null
@@ -1,51 +0,0 @@
-<?php
-
-/**
- * Contains functionality shared by Paymentform test cases.
- */
-class PaymentformWebTestCase extends DrupalWebTestCase {
-
-  function setUp(array $modules = array()) {
-    parent::setUp($modules + array('field', 'node', 'paymentform'));
-
-    // Field configuration.
-    $this->field_paymentform = field_create_field(array(
-      'field_name' => 'field_paymentform',
-      'type' => 'paymentform',
-      'cardinality' => 2,
-    ));
-    $this->field_paymentform_instance = field_create_instance(array(
-      'field_name' => 'field_paymentform',
-      'entity_type' => 'node',
-      'bundle' => 'page',
-      'widget' => array(
-        'type' => 'paymentform_line_item',
-      ),
-    ));
-    $this->PaymentLineItemData = array(
-      'amount' => 1.0,
-      'description' => 'foo',
-      'name' => 'bar',
-      'quantity' => 1,
-      'tax_rate' => 0.0,
-    );
-  }
-
-  /**
-   * Checks if a FieldValidationException contains a specified error code.
-   *
-   * @param FieldValidationException $e
-   * @param string $code
-   *
-   * @return boolean
-   */
-  function fieldValidationExceptionError(FieldValidationException $e, $code) {
-    $codes = array();
-    foreach ($e->errors['field_paymentform'][LANGUAGE_NONE][0] as $error) {
-      if ($error['error'] == $code) {
-        return TRUE;
-      }
-    }
-    return FALSE;
-  }
-}
\ No newline at end of file
diff --git a/paymentmethodbasic/tests/paymentmethodbasic_test/paymentmethodbasic_test.info b/paymentmethodbasic/tests/paymentmethodbasic_test/paymentmethodbasic_test.info
index 3cfef6f..735d0e0 100644
--- a/paymentmethodbasic/tests/paymentmethodbasic_test/paymentmethodbasic_test.info
+++ b/paymentmethodbasic/tests/paymentmethodbasic_test/paymentmethodbasic_test.info
@@ -5,5 +5,5 @@ dependencies[] = paymentmethodbasic
 dependencies[] = xtools
 package = Payment
 hidden = TRUE
-files[] = tests/PaymentmethodbasicCallablesWebTestCase.test
-files[] = tests/PaymentMethodBasicTestPaymentMethodBasicControllerWebTestCase.test
\ No newline at end of file
+files[] = tests/PaymentmethodbasicTestCallablesWebTestCase.test
+files[] = tests/PaymentmethodbasicTestPaymentMethodBasicControllerWebTestCase.test
diff --git a/paymentmethodbasic/tests/paymentmethodbasic_test/tests/PaymentMethodBasicTestPaymentMethodBasicControllerWebTestCase.test b/paymentmethodbasic/tests/paymentmethodbasic_test/tests/PaymentMethodBasicTestPaymentMethodBasicControllerWebTestCase.test
deleted file mode 100644
index 8479525..0000000
--- a/paymentmethodbasic/tests/paymentmethodbasic_test/tests/PaymentMethodBasicTestPaymentMethodBasicControllerWebTestCase.test
+++ /dev/null
@@ -1,95 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains class PaymentMethodBasicTestPaymentMethodBasicControllerWebTestCase.
- */
-
-/**
- * Tests PaymentMethodBasicController functionality.
- */
-class PaymentMethodBasicTestPaymentMethodBasicControllerWebTestCase extends PaymentWebTestCase {
-
-  static function getInfo() {
-    return array(
-      'name' => 'PaymentMethodBasicController functionality',
-      'group' => 'Basic Payment Method',
-      'dependencies' => array('paymentmethodbasic_test'),
-    );
-  }
-
-  function setUp(array $modules = array()) {
-    parent::setUp(array('paymentmethodbasic_test'));
-  }
-
-  /**
-   * Test CRUD functionality.
-   */
-  function testCRUD() {
-    $payment_method = new PaymentMethod(array(
-      'controller' => payment_method_controller_load('PaymentMethodBasicController'),
-      'controller_data' => array(
-        'message' => 'foo',
-        'status' => PAYMENT_STATUS_FAILED,
-        'text_format' => 'bar',
-      ),
-    ));
-    entity_save('payment_method', $payment_method);
-    $pmid = $payment_method->pmid;
-    $count = db_query("SELECT COUNT(1) FROM {paymentmethodbasic} WHERE pmid = :pmid AND message = :message AND status = :status AND text_format = :text_format", array(
-      ':pmid' => $pmid,
-      ':message' => $payment_method->controller_data['message'],
-      ':status' => $payment_method->controller_data['status'],
-      ':text_format' => $payment_method->controller_data['text_format'],
-    ))->fetchField();
-    $this->assertTrue($count, "A new BasicPaymentMethodController payment method's controller data is inserted correctly.");
-
-    // Test loading a payment method.
-    $payment_method_loaded = entity_load_single('payment_method', $pmid);
-    $this->assertFalse(array_diff_assoc($payment_method->controller_data, $payment_method_loaded->controller_data), "An BasicPaymentMethodController payment method's controller data is loaded correctly.");
-
-    // Test updating a payment method.
-    $payment_method->controller_data = array(
-      'message' => 'foo',
-      'status' => PAYMENT_STATUS_NEW,
-      'text_format' => 'bar',
-    );
-    entity_save('payment_method', $payment_method);
-    $count = db_query("SELECT COUNT(1) FROM {paymentmethodbasic} WHERE pmid = :pmid AND message = :message AND status = :status AND text_format = :text_format", array(
-      ':pmid' => $pmid,
-      ':message' => $payment_method->controller_data['message'],
-      ':status' => $payment_method->controller_data['status'],
-      ':text_format' => $payment_method->controller_data['text_format'],
-    ))->fetchField();
-    $this->assertTrue($count, "An BasicPaymentMethodController payment method's controller data is updated correctly.");
-
-    // Test deleting a payment method.
-    entity_delete('payment_method', $pmid);
-    $count = db_query("SELECT COUNT(1) FROM {paymentmethodbasic} WHERE pmid = :pmid", array(
-      ':pmid' => $pmid,
-    ))->fetchField();
-    $this->assertFalse($count, "An BasicPaymentMethodController payment method's controller data is deleted when the payment method is deleted.");
-  }
-
-  /**
-   * Test
-   * BasicPaymentMethodController::payment_method_configuration_form_elements_callback.
-   */
-  function testPaymentMethodFormCallback() {
-    $account = $this->drupalCreateUser(array('payment.payment_method.create.PaymentMethodBasicController'));
-    $this->drupalLogin($account);
-    $this->drupalPost('admin/config/services/payment/method/add/PaymentMethodBasicController', array(
-      'title_specific' => 'Foo',
-      'name' => 'foo',
-      'controller_form[message][value]' => 'bar',
-      'controller_form[status]' => PAYMENT_STATUS_FAILED,
-    ), t('Save'));
-    $payment_method = entity_load_single('payment_method', 1);
-    $reference = array(
-      'message' => 'bar',
-      'status' => PAYMENT_STATUS_FAILED,
-      'text_format' => 'plain_text',
-    );
-    $this->assertFalse(array_diff_assoc($reference, $payment_method->controller_data), "An BasicPaymentMethodController payment method's controller data is correctly saved by the payment method form.");
-  }
-}
\ No newline at end of file
diff --git a/paymentmethodbasic/tests/paymentmethodbasic_test/tests/PaymentmethodbasicCallablesWebTestCase.test b/paymentmethodbasic/tests/paymentmethodbasic_test/tests/PaymentmethodbasicCallablesWebTestCase.test
deleted file mode 100644
index c9a4ee6..0000000
--- a/paymentmethodbasic/tests/paymentmethodbasic_test/tests/PaymentmethodbasicCallablesWebTestCase.test
+++ /dev/null
@@ -1,20 +0,0 @@
-<?php
-
-class PaymentmethodbasicCallablesWebTestCase extends PaymentWebTestCase {
-
-  static function getInfo() {
-    return array(
-      'name' => "Callables",
-      'group' => 'Basic Payment Method',
-      'dependencies' => array('paymentmethodbasic', 'paymentmethodbasic_test', 'xtools'),
-    );
-  }
-
-  function setUp(array $modules = array()) {
-    parent::setUp($modules + array('xtools'));
-  }
-
-  function testCallables() {
-    $this->XtoolsAssertCallables(array('paymentmethodbasic', 'paymentmethodbasic_test'), array('drupal', 'payment'));
-  }
-}
\ No newline at end of file
diff --git a/paymentmethodbasic/tests/paymentmethodbasic_test/tests/PaymentmethodbasicTestCallablesWebTestCase.test b/paymentmethodbasic/tests/paymentmethodbasic_test/tests/PaymentmethodbasicTestCallablesWebTestCase.test
new file mode 100644
index 0000000..872fe51
--- /dev/null
+++ b/paymentmethodbasic/tests/paymentmethodbasic_test/tests/PaymentmethodbasicTestCallablesWebTestCase.test
@@ -0,0 +1,34 @@
+<?php
+
+/**
+ * @file
+ * Contains class PaymentmethodbasicTestCallablesWebTestCase.
+ */
+
+/**
+ * Tests implementations of callables.
+ */
+class PaymentmethodbasicTestCallablesWebTestCase extends PaymentWebTestCase {
+
+  static function getInfo() {
+    return array(
+      'name' => 'Hook and callback implementations',
+      'group' => 'Basic Payment Method',
+      'dependencies' => array('paymentmethodbasic', 'paymentmethodbasic_test', 'xtools'),
+    );
+  }
+  /**
+   * Overrides parent::setUp().
+   */
+
+  /**
+   * Overrides parent::setUp().
+   */
+  function setUp(array $modules = array()) {
+    parent::setUp($modules + array('xtools'));
+  }
+
+  function testCallables() {
+    $this->XtoolsAssertCallables(array('paymentmethodbasic', 'paymentmethodbasic_test'), array('drupal', 'payment'));
+  }
+}
diff --git a/paymentmethodbasic/tests/paymentmethodbasic_test/tests/PaymentmethodbasicTestPaymentMethodBasicControllerWebTestCase.test b/paymentmethodbasic/tests/paymentmethodbasic_test/tests/PaymentmethodbasicTestPaymentMethodBasicControllerWebTestCase.test
new file mode 100644
index 0000000..678dfe9
--- /dev/null
+++ b/paymentmethodbasic/tests/paymentmethodbasic_test/tests/PaymentmethodbasicTestPaymentMethodBasicControllerWebTestCase.test
@@ -0,0 +1,101 @@
+<?php
+
+/**
+ * @file
+ * Contains class PaymentMethodBasicTestPaymentMethodBasicControllerWebTestCase.
+ */
+
+/**
+ * Tests PaymentMethodBasicController functionality.
+ */
+class PaymentMethodBasicTestPaymentMethodBasicControllerWebTestCase extends PaymentWebTestCase {
+
+  static function getInfo() {
+    return array(
+      'name' => 'PaymentMethodBasicController functionality',
+      'group' => 'Basic Payment Method',
+      'dependencies' => array('paymentmethodbasic_test'),
+    );
+  }
+  /**
+   * Overrides parent::setUp().
+   */
+
+  /**
+   * Overrides parent::setUp().
+   */
+  function setUp(array $modules = array()) {
+    parent::setUp(array('paymentmethodbasic_test'));
+  }
+
+  /**
+   * Test CRUD functionality.
+   */
+  function testCRUD() {
+    $payment_method = new PaymentMethod(array(
+      'controller' => payment_method_controller_load('PaymentMethodBasicController'),
+      'controller_data' => array(
+        'message' => 'foo',
+        'status' => PAYMENT_STATUS_FAILED,
+        'text_format' => 'bar',
+      ),
+    ));
+    entity_save('payment_method', $payment_method);
+    $pmid = $payment_method->pmid;
+    $count = db_query("SELECT COUNT(1) FROM {paymentmethodbasic} WHERE pmid = :pmid AND message = :message AND status = :status AND text_format = :text_format", array(
+      ':pmid' => $pmid,
+      ':message' => $payment_method->controller_data['message'],
+      ':status' => $payment_method->controller_data['status'],
+      ':text_format' => $payment_method->controller_data['text_format'],
+    ))->fetchField();
+    $this->assertTrue($count, "A new BasicPaymentMethodController payment method's controller data is inserted correctly.");
+
+    // Test loading a payment method.
+    $payment_method_loaded = entity_load_single('payment_method', $pmid);
+    $this->assertFalse(array_diff_assoc($payment_method->controller_data, $payment_method_loaded->controller_data), "An BasicPaymentMethodController payment method's controller data is loaded correctly.");
+
+    // Test updating a payment method.
+    $payment_method->controller_data = array(
+      'message' => 'foo',
+      'status' => PAYMENT_STATUS_NEW,
+      'text_format' => 'bar',
+    );
+    entity_save('payment_method', $payment_method);
+    $count = db_query("SELECT COUNT(1) FROM {paymentmethodbasic} WHERE pmid = :pmid AND message = :message AND status = :status AND text_format = :text_format", array(
+      ':pmid' => $pmid,
+      ':message' => $payment_method->controller_data['message'],
+      ':status' => $payment_method->controller_data['status'],
+      ':text_format' => $payment_method->controller_data['text_format'],
+    ))->fetchField();
+    $this->assertTrue($count, "An BasicPaymentMethodController payment method's controller data is updated correctly.");
+
+    // Test deleting a payment method.
+    entity_delete('payment_method', $pmid);
+    $count = db_query("SELECT COUNT(1) FROM {paymentmethodbasic} WHERE pmid = :pmid", array(
+      ':pmid' => $pmid,
+    ))->fetchField();
+    $this->assertFalse($count, "An BasicPaymentMethodController payment method's controller data is deleted when the payment method is deleted.");
+  }
+
+  /**
+   * Test
+   * BasicPaymentMethodController::payment_method_configuration_form_elements_callback.
+   */
+  function testPaymentMethodFormCallback() {
+    $account = $this->drupalCreateUser(array('payment.payment_method.create.PaymentMethodBasicController'));
+    $this->drupalLogin($account);
+    $this->drupalPost('admin/config/services/payment/method/add/PaymentMethodBasicController', array(
+      'title_specific' => 'Foo',
+      'name' => 'foo',
+      'controller_form[message][value]' => 'bar',
+      'controller_form[status]' => PAYMENT_STATUS_FAILED,
+    ), t('Save'));
+    $payment_method = entity_load_single('payment_method', 1);
+    $reference = array(
+      'message' => 'bar',
+      'status' => PAYMENT_STATUS_FAILED,
+      'text_format' => 'plain_text',
+    );
+    $this->assertFalse(array_diff_assoc($reference, $payment_method->controller_data), "An BasicPaymentMethodController payment method's controller data is correctly saved by the payment method form.");
+  }
+}
diff --git a/paymentreference/tests/paymentreference_test/paymentreference_test.info b/paymentreference/tests/paymentreference_test/paymentreference_test.info
index 3680324..2baa424 100644
--- a/paymentreference/tests/paymentreference_test/paymentreference_test.info
+++ b/paymentreference/tests/paymentreference_test/paymentreference_test.info
@@ -5,5 +5,5 @@ dependencies[] = paymentreference
 dependencies[] = xtools
 package = Payment
 hidden = TRUE
-files[] = tests/PaymentreferenceCallablesWebTestCase.test
-files[] = tests/PaymentreferenceTestQueueWebTestCase.test
\ No newline at end of file
+files[] = tests/PaymentreferenceTestCallablesWebTestCase.test
+files[] = tests/PaymentreferenceTestQueueWebTestCase.test
diff --git a/paymentreference/tests/paymentreference_test/tests/PaymentreferenceCallablesWebTestCase.test b/paymentreference/tests/paymentreference_test/tests/PaymentreferenceCallablesWebTestCase.test
deleted file mode 100644
index 17b5d0d..0000000
--- a/paymentreference/tests/paymentreference_test/tests/PaymentreferenceCallablesWebTestCase.test
+++ /dev/null
@@ -1,20 +0,0 @@
-<?php
-
-class PaymentreferenceCallablesWebTestCase extends PaymentWebTestCase {
-
-  static function getInfo() {
-    return array(
-      'name' => "Callables",
-      'group' => 'Payment Reference',
-      'dependencies' => array('paymentreference', 'paymentreference_test', 'xtools'),
-    );
-  }
-
-  function setUp(array $modules = array()) {
-    parent::setUp($modules + array('xtools'));
-  }
-
-  function testCallables() {
-    $this->XtoolsAssertCallables(array('paymentreference', 'paymentreference_test'), array('drupal'));
-  }
-}
\ No newline at end of file
diff --git a/paymentreference/tests/paymentreference_test/tests/PaymentreferenceTestCallablesWebTestCase.test b/paymentreference/tests/paymentreference_test/tests/PaymentreferenceTestCallablesWebTestCase.test
new file mode 100644
index 0000000..2344d06
--- /dev/null
+++ b/paymentreference/tests/paymentreference_test/tests/PaymentreferenceTestCallablesWebTestCase.test
@@ -0,0 +1,34 @@
+<?php
+
+/**
+ * @file
+ * Contains class PaymentreferenceTestCallablesWebTestCase.
+ */
+
+/**
+ * Tests implementations of callables.
+ */
+class PaymentreferenceTestCallablesWebTestCase extends PaymentWebTestCase {
+
+  static function getInfo() {
+    return array(
+      'name' => 'Hook and callback implementations',
+      'group' => 'Payment Reference',
+      'dependencies' => array('paymentreference', 'paymentreference_test', 'xtools'),
+    );
+  }
+  /**
+   * Overrides parent::setUp().
+   */
+
+  /**
+   * Overrides parent::setUp().
+   */
+  function setUp(array $modules = array()) {
+    parent::setUp($modules + array('xtools'));
+  }
+
+  function testCallables() {
+    $this->XtoolsAssertCallables(array('paymentreference', 'paymentreference_test'), array('drupal'));
+  }
+}
diff --git a/paymentreference/tests/paymentreference_test/tests/PaymentreferenceTestQueueWebTestCase.test b/paymentreference/tests/paymentreference_test/tests/PaymentreferenceTestQueueWebTestCase.test
index 367f743..4088ce0 100644
--- a/paymentreference/tests/paymentreference_test/tests/PaymentreferenceTestQueueWebTestCase.test
+++ b/paymentreference/tests/paymentreference_test/tests/PaymentreferenceTestQueueWebTestCase.test
@@ -1,5 +1,13 @@
 <?php
 
+/**
+ * @file
+ * Contains class PaymentreferenceTestQueueWebTestCase.
+ */
+
+/**
+ * Tests the reference queue.
+ */
 class PaymentreferenceTestQueueWebTestCase extends PaymentWebTestCase {
 
   static function getInfo() {
@@ -8,7 +16,13 @@ class PaymentreferenceTestQueueWebTestCase extends PaymentWebTestCase {
       'group' => 'Payment Reference',
     );
   }
+  /**
+   * Overrides parent::setUp().
+   */
 
+  /**
+   * Overrides parent::setUp().
+   */
   function setUp(array $modules = array()) {
     parent::setUp($modules + array('paymentreference'));
   }
@@ -111,4 +125,4 @@ class PaymentreferenceTestQueueWebTestCase extends PaymentWebTestCase {
     $pid = paymentreference_load($entity_type, $bundles[3], $field_name, 2);
     $this->assertFalse($pid, 'When deleting a field, all payments associated with it are removed from the queue.');
   }
-}
\ No newline at end of file
+}
