diff --git a/multiple_value_widget.info b/multiple_value_widget.info
index 419762a..112109a 100644
--- a/multiple_value_widget.info
+++ b/multiple_value_widget.info
@@ -2,3 +2,5 @@ name = Multiple Value Widget
 description = Make multiple value forms more user friendly.
 core = 7.x
 package = Fields
+
+files[] = tests/multiple_value_widget.test
diff --git a/tests/multiple_value_widget.test b/tests/multiple_value_widget.test
new file mode 100644
index 0000000..689eb07
--- /dev/null
+++ b/tests/multiple_value_widget.test
@@ -0,0 +1,236 @@
+<?php
+
+/**
+ * Test for Multiple Value Widget.
+ */
+class MultipleValueWidgetTestCase extends DrupalWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Core tests',
+      'description' => 'Tests the core functionality of Multiple Value Widget.',
+      'group' => 'Multiple Value Widget',
+    );
+  }
+
+  public function setUp() {
+    parent::setUp('multiple_value_widget');
+    $this->drupalLogin($this->getAdminUser());
+    $this->configureContentType();
+  }
+
+  /**
+   * Returns a user with administration rights.
+   *
+   * @param $permissions
+   *   Additional permissions for administrative user.
+   */
+  protected function getAdminUser(array $permissions = array()) {
+    return $this->drupalCreateUser(array_merge(array(
+      'bypass node access',
+      'administer nodes',
+      'administer fields',
+      'administer content types',
+      'access administration pages',
+      'administer site configuration',
+    ), $permissions));
+  }
+
+  /**
+   * Configures the "Basic page" content type for entity translation tests.
+   */
+  public function configureContentType() {
+    // Set body field's cardinality to unlimited.
+    $edit = array();
+    $edit['field[cardinality]'] = -1;
+    $edit['instance[widget][settings][multiple_value_widget]'] = 'tabs';
+    $this->drupalPost('admin/structure/types/manage/page/fields/body', $edit, t('Save settings'));
+    $this->assertRaw(t('Saved %field configuration.', array('%field' => 'Body')), t('Body field settings have been updated.'));
+
+    // Check if the setting works.
+    $this->drupalGet('node/add/page');
+    $this->assertFieldById('edit-body-und-add-more', t('Add another item'), t('Add another item button found.'));
+
+    // Field with unlimited cardinality and FIELD_BEHAVIOR_CUSTOM.
+    $field_list = array(
+      'field_name' => 'field_list',
+      'type' => 'list_integer',
+      'cardinality' => -1,
+      'settings' => array(
+        'allowed_values' => array(
+          0 => 'Zero',
+          1 => 'One',
+          2 => 'Two',
+          3 => 'Three',
+        ),
+      ),
+    );
+    field_create_field($field_list);
+
+    $instance = array(
+      'field_name' => 'field_list',
+      'entity_type' => 'node',
+      'bundle' => 'page',
+      'widget' => array(
+        'type' => 'options_buttons',
+      ),
+    );
+    field_create_instance($instance);
+
+    // Field with cardinality 1.
+    $field_single_text = array(
+      'field_name' => 'field_single_text',
+      'cardinality' => 1,
+      'type' => 'text',
+      'settings' => array(
+        'max_length' => 50,
+      ),
+    );
+    field_create_field($field_single_text);
+    $instance = array(
+      'field_name' => 'field_single_text',
+      'entity_type' => 'node',
+      'bundle' => 'page',
+      'widget' => array(
+        'type' => 'text_textfield',
+      ),
+      'display' => array(
+        'default' => array(
+          'type' => 'text_default',
+        ),
+      ),
+    );
+    field_create_instance($instance);
+
+  }
+
+  /**
+   * Tests theme registry expectations.
+   *
+   * @see multiple_value_widget_theme_registry_alter()
+   */
+  public function testThemeRegistry() {
+    $hooks = theme_get_registry(FALSE);
+    if (isset($hooks['field_multiple_value_form'])) {
+      $this->assertEqual($hooks['field_multiple_value_form']['function'], 'multiple_value_widget_field_multiple_value_form');
+    }
+    if (isset($hooks['file_widget_multiple'])) {
+      $this->assertEqual($hooks['file_widget_multiple']['function'], 'multiple_value_widget_file_widget_multiple');
+    }
+
+  }
+
+  /**
+   * Test FieldUI functionality.
+   *
+   * @see multiple_value_widget_form_field_ui_field_edit_form_alter()
+   */
+  public function testFieldManagementInterface() {
+    $this->drupalGet('admin/structure/types/manage/page/fields/body');
+
+    // Look for the following xpath expressions.
+    $xpaths = array(
+      '//div[@id="edit-instance-widget-settings-multiple-value-widget"]',
+      $this->constructFieldXpath('id', 'edit-instance-widget-settings-multiple-value-widget-table'),
+      $this->constructFieldXpath('id', 'edit-instance-widget-settings-multiple-value-widget-tabs'),
+      $this->constructFieldXpath('id', 'edit-instance-widget-settings-multiple-value-widget-blocks'),
+      $this->constructFieldXpath('id', 'edit-instance-widget-settings-multiple-value-widget-accordion'),
+    );
+    foreach ($xpaths as $xpath) {
+      $results = count($this->xpath($xpath));
+      $this->assertEqual($results, 1);
+    }
+
+    // Check that the previous xpath expressions don't target anything.
+    // This is testing the FIELD_BEHAVIOR_DEFAULT vs FIELD_BEHAVIOR_CUSTOM.
+    $this->drupalGet('admin/structure/types/manage/page/fields/field_list');
+    foreach ($xpaths as $xpath) {
+      $results = count($this->xpath($xpath));
+      $this->assertEqual($results, 0);
+    }
+
+    // Check that the previous xpath expressions target anything.
+    // This is testing CARDINALITY = 1 for a field with FIELD_BEHAVIOR_DEFAULT.
+    // In reality, the fields are hidden for CARDINALITY = 1 via #states.
+    $this->drupalGet('admin/structure/types/manage/page/fields/field_single_text');
+    foreach ($xpaths as $xpath) {
+      $results = count($this->xpath($xpath));
+      $this->assertEqual($results, 1);
+    }
+
+  }
+
+  /**
+   * Test generated HTML markup.
+   *
+   * @see theme_multiple_value_widget_group()
+   */
+  public function testGeneratedHtml() {
+    $module_path = drupal_get_path('module', 'multiple_value_widget');
+
+    // Body is set to 'tabs' initially.
+    $this->drupalGet('node/add/page');
+    $xpath = '//ul[contains(@class, "mvw-tabs")]//a[@href="#mvw-group-body-0"]';
+    $results = count($this->xpath($xpath));
+    $this->assertEqual($results, 1);
+    // Check that we get the standard title.
+    $xpath = '//ul[contains(@class, "mvw-tabs")]//a[@href="#mvw-group-body-0"]/text()';
+    $results = $this->xpath($xpath);
+    $tab_title = (string) reset($results);
+    $this->assertEqual($tab_title, 'Body (1)');
+    // Check that the tabs specific assets/settings are present.
+    $this->assertRaw('"mvw":{"mvw-body":"tabs"}');
+    $this->assertRaw('jquery.ui.tabs');
+
+    // Body is set anew to 'blocks'.
+    $edit = array(
+      'instance[widget][settings][multiple_value_widget]' => 'blocks',
+    );
+    $this->drupalPost('admin/structure/types/manage/page/fields/body', $edit, t('Save settings'));
+    $this->assertRaw(t('Saved %field configuration.', array('%field' => 'Body')), t('Body field settings have been updated.'));
+    $this->drupalGet('node/add/page');
+    $xpath = '//div[contains(@class, "mvw-group")]/div[@class="mvw-group-title ui-widget-header ui-corner-all"]';
+    $results = count($this->xpath($xpath));
+    $this->assertEqual($results, 1);
+    // Check that the blocks specific settings are present.
+    $this->assertRaw('"mvw":{"mvw-body":"blocks"}');
+
+    // Body is set anew to 'accordion' and cardinality to 2.
+    $edit = array(
+      'instance[widget][settings][multiple_value_widget]' => 'accordion',
+      'field[cardinality]' => 2,
+    );
+    $this->drupalPost('admin/structure/types/manage/page/fields/body', $edit, t('Save settings'));
+    $this->assertRaw(t('Saved %field configuration.', array('%field' => 'Body')), t('Body field settings have been updated.'));
+    $this->drupalGet('node/add/page');
+    $xpath = '//div[contains(@class, "mvw-group")]//span[@class="ui-icon ui-icon-arrowthick-2-n-s"]';
+    $results = count($this->xpath($xpath));
+    $this->assertEqual($results, 2);
+    // Check that the accordion specific assets/settings are present.
+    $this->assertRaw('"mvw":{"mvw-body":"accordion"}');
+    $this->assertRaw('jquery.ui.accordion');
+
+    // Check that the rest of the assets are added correctly.
+    $this->assertRaw($module_path . '/multiple_value_widget.js');
+    $this->assertRaw($module_path . '/multiple_value_widget.css');
+    $this->assertRaw('jquery.ui.sortable');
+  }
+
+  /**
+   * Test API.
+   *
+   * @see hook_multiple_value_widget_element_title_alter()
+   */
+  public function testApi() {
+
+    module_enable(array('multiple_value_widget_test'));
+
+    // Body is set to 'tabs' initially.
+    $this->drupalGet('node/add/page');
+    $xpath = '//ul[contains(@class, "mvw-tabs")]//a[@href="#mvw-group-body-0"]/text()';
+    $results = $this->xpath($xpath);
+    $tab_title = (string) reset($results);
+    $this->assertEqual($tab_title, MULTIPLE_VALUE_WIDGET_TEST_MODIFIED_TITLE);
+  }
+
+}
diff --git a/tests/multiple_value_widget_test/multiple_value_widget_test.info b/tests/multiple_value_widget_test/multiple_value_widget_test.info
new file mode 100644
index 0000000..d3366ba
--- /dev/null
+++ b/tests/multiple_value_widget_test/multiple_value_widget_test.info
@@ -0,0 +1,8 @@
+name = Multiple Value Widget testing
+description = Tests Multiple Value Widget module functionality. Do not enable.
+core = 7.x
+package = Testing
+hidden = TRUE
+dependencies[] = multiple_value_widget
+
+files[] = multiple_value_widget_test.module
diff --git a/tests/multiple_value_widget_test/multiple_value_widget_test.module b/tests/multiple_value_widget_test/multiple_value_widget_test.module
new file mode 100644
index 0000000..27b7e79
--- /dev/null
+++ b/tests/multiple_value_widget_test/multiple_value_widget_test.module
@@ -0,0 +1,10 @@
+<?php
+
+define("MULTIPLE_VALUE_WIDGET_TEST_MODIFIED_TITLE", "Hello world.");
+
+/**
+ * Implements hook_multiple_value_widget_element_title_alter().
+ */
+function multiple_value_widget_test_multiple_value_widget_element_title_alter(&$title, $element) {
+  $title = MULTIPLE_VALUE_WIDGET_TEST_MODIFIED_TITLE;
+}
