diff --git a/similarterms.info b/similarterms.info
index bdd2650..f382093 100644
--- a/similarterms.info
+++ b/similarterms.info
@@ -1,5 +1,9 @@
-core = "6.x"
+core = "7.x"
 dependencies[] = "views"
 description = "Use Views to show similar content based on taxonomy terms"
 name = "Similar By Terms"
 package = "Views"
+files[] = views/similarterms_handler_argument_node_nid.inc
+files[] = views/similarterms_handler_field_similar.inc
+files[] = views/similarterms_handler_sort_similar.inc
+files[] = similarterms.test
diff --git a/similarterms.module b/similarterms.module
index b40d1a2..cd7178a 100644
--- a/similarterms.module
+++ b/similarterms.module
@@ -6,7 +6,7 @@
   */
 function similarterms_views_api() {
   return array(
-    'api' => 2,
+    'api' => 3,
     'path' => drupal_get_path('module', 'similarterms') . '/views',
   );
 }
\ No newline at end of file
diff --git a/similarterms.test b/similarterms.test
new file mode 100644
index 0000000..96d33e8
--- /dev/null
+++ b/similarterms.test
@@ -0,0 +1,303 @@
+<?php
+
+/**
+ * @file
+ * Definition of similarTermsTestCase.
+ *
+ * @todo
+ * - Test the vocbular option in the argument handler.
+ * - Test the field_similar, sort_similar handler.
+ */
+
+/**
+ * Tests functionality of similar terms module.
+ */
+class similarTermsTestCase extends TaxonomyWebTestCase {
+  /**
+   * Stores all nids.
+   * @var array
+   */
+  public $nids;
+
+  /**
+   * Stores all tids.
+   * @var array
+   */
+  public $tids;
+
+  /**
+   * Stores all node-id's keyed by tid.
+   * @var array
+   */
+  public $nodes_per_term;
+
+  /**
+   * Contains the used vocabulary.
+   */
+  public $vocabulary;
+  public $node_type;
+  public $field;
+  public $field_name;
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Similarterms',
+      'description' => 'Test the Similarterms module',
+      'group' => 'Similarterms',
+    );
+  }
+  protected function setUp() {
+    parent::setUp('views', 'taxonomy', 'node', 'similarterms');
+
+    // Create a vocabulary and some terms.
+    $this->vocabulary = $this->createVocabulary();
+    for ($i = 0; $i < 3; $i++) {
+      $term = $this->createTerm($this->vocabulary);
+      $this->tids[] = $term->tid;
+    }
+
+    // Create a nodetype and attach a taxonomy field to it.
+    $this->node_type = $this->drupalCreateContentType();
+    $this->field_name = 'field_test_taxonomy';
+    $this->field = array(
+      'field_name' => $this->field_name,
+      'type' => 'taxonomy_term_reference',
+      'cardinality' => FIELD_CARDINALITY_UNLIMITED,
+      'settings' => array(
+        'allowed_values' => array(
+          array(
+            'vocabulary' => $this->vocabulary->machine_name,
+            'parent' => 0,
+          ),
+        ),
+      ),
+    );
+    field_create_field($this->field);
+    $this->instance = array(
+      'field_name' => $this->field_name,
+      'bundle' => $this->node_type->type,
+      'entity_type' => 'node',
+      'widget' => array(
+        'type' => 'options_select',
+      ),
+      'display' => array(
+        'default' => array(
+          'type' => 'taxonomy_term_reference_link',
+        ),
+      ),
+    );
+    field_create_instance($this->instance);
+
+
+    // Create the used nodes.
+    // First create a node with a term which is not used by other nodes.
+    $this->createNodeWithTerm($this->tids[0]);
+    // Create a node with a term which is is used by the third node as well.
+    $this->createNodeWithTerm($this->tids[1]);
+    // The third node should have the term of the second and forth.
+    $this->createNodeWithTerm(array($this->tids[1], $this->tids[2]));
+    $this->createNodeWithTerm(array($this->tids[2]));
+  }
+
+  /**
+   * Create a node with certain terms.
+   * @param array $tids
+   *   An array of all taxonomy terms.
+   * @param array $edit
+   *   The edit array @see DrupalWebTestCase::drupalCreateNode.
+   */
+  public function createNodeWithTerm($tids, array $edit = array()) {
+    $tids = (array) $tids;
+    if (!isset($edit['type'])) {
+      $edit['type'] = $this->node_type->type;
+    }
+    foreach ($tids as $tid) {
+      $edit[$this->field_name][LANGUAGE_NONE][] = array('tid' => $tid);
+    }
+
+    $node = $this->drupalCreateNode($edit);
+    $this->nids[] = $node->nid;
+    foreach ($tids as $tid) {
+      $this->nodes_per_term[$tid][] = $node->nid;
+    }
+  }
+
+  function testSimilarTerms() {
+    $nid_alias = 'node_nid';
+
+    foreach ($this->nids as $nid) {
+      $node = node_load($nid);
+      $view = $this->viewSimilarTerms();
+      $view->set_display();
+      $view->pre_execute(array($nid));
+      $view->execute();
+      switch ($nid) {
+        case 1:
+          $this->assertEqual(count($view->result), 0, "Take sure that a node without a similar term doesn't generate a view result");
+          break;
+        case 2:
+          $this->assertEqual(count($view->result), 1, "Take sure that the right amount of result are returned");
+          $this->assertIdenticalResultset($view, array(array($nid_alias => 3)));
+          break;
+
+        case 3:
+          $this->assertEqual(count($view->result), 2, "Take sure that the right amount of result are returned");
+          $this->assertIdenticalResultset($view, array(array($nid_alias => 2), array($nid_alias => 4)));
+          break;
+
+        case 4:
+          $this->assertEqual(count($view->result), 1, "Take sure that the right amount of result are returned");
+          $this->assertIdenticalResultset($view, array(array($nid_alias => 4)));
+          break;
+
+      }
+
+      $view->destroy();
+    }
+  }
+
+  function testSimilarTermsIncludeArgs() {
+    foreach ($this->nids as $nid) {
+      $node = node_load($nid);
+      $view = $this->viewSimilarTerms();
+      $view->set_display();
+      $view->pre_execute(array($nid));
+      $view->argument['nid']->options['include_args'] = TRUE;
+      $view->execute();
+      switch ($nid) {
+        case 1:
+          $this->assertEqual(count($view->result), 1, "Take sure that a node without a similar term doesn't generate a view result");
+          $this->assertIdenticalResultset($view, array(array('nid' => 1)), array('node_nid' => 'nid'));
+          break;
+        case 2:
+          $this->assertEqual(count($view->result), 2, "Take sure that the right amount of result are returned");
+          $this->assertIdenticalResultset($view, array(array('nid' => 2), array('nid' => 3)), array('node_nid' => 'nid'));
+          break;
+
+        case 3:
+          $this->assertEqual(count($view->result), 3, "Take sure that the right amount of result are returned");
+          $this->assertIdenticalResultset($view, array(array('nid' => 2), array('nid' => 3), array('nid' => 4)), array('node_nid' => 'nid'));
+          break;
+
+        case 4:
+          $this->assertEqual(count($view->result), 2, "Take sure that the right amount of result are returned");
+          $this->assertIdenticalResultset($view, array(array('nid' => 3), array('nid' => 4)), array('node_nid' => 'nid'));
+          break;
+
+      }
+
+      $view->destroy();
+    }
+  }
+
+  public function viewSimilarTerms() {
+    $view = new view;
+    $view->name = 'test_similarterms';
+    $view->description = '';
+    $view->tag = 'default';
+    $view->base_table = 'node';
+    $view->human_name = 'test_similarterms';
+    $view->core = 7;
+    $view->api_version = '3.0';
+    $view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
+
+    /* Display: Master */
+    $handler = $view->new_display('default', 'Master', 'default');
+    $handler->display->display_options['title'] = 'test';
+    $handler->display->display_options['access']['type'] = 'perm';
+    $handler->display->display_options['cache']['type'] = 'none';
+    $handler->display->display_options['query']['type'] = 'views_query';
+    $handler->display->display_options['query']['options']['distinct'] = TRUE;
+    $handler->display->display_options['exposed_form']['type'] = 'basic';
+    $handler->display->display_options['pager']['type'] = 'full';
+    $handler->display->display_options['pager']['options']['items_per_page'] = '10';
+    $handler->display->display_options['style_plugin'] = 'default';
+    $handler->display->display_options['row_plugin'] = 'fields';
+    /* Contextual filter: Similar By Terms: Nid */
+    $handler->display->display_options['arguments']['nid']['id'] = 'nid';
+    $handler->display->display_options['arguments']['nid']['table'] = 'similarterms';
+    $handler->display->display_options['arguments']['nid']['field'] = 'nid';
+    $handler->display->display_options['arguments']['nid']['default_argument_type'] = 'fixed';
+    $handler->display->display_options['arguments']['nid']['summary']['number_of_records'] = '0';
+    $handler->display->display_options['arguments']['nid']['summary']['format'] = 'default_summary';
+    $handler->display->display_options['arguments']['nid']['summary_options']['items_per_page'] = '25';
+    $handler->display->display_options['arguments']['nid']['vocabularies'] = array(
+      1 => 0,
+    );
+    $handler->display->display_options['arguments']['nid']['include_args'] = 0;
+    /* Sort criterion: Content: Nid */
+    $handler->display->display_options['sorts']['nid']['id'] = 'nid';
+    $handler->display->display_options['sorts']['nid']['table'] = 'node';
+    $handler->display->display_options['sorts']['nid']['field'] = 'nid';
+
+    return $view;
+  }
+
+  /**
+   * Helper function: verify a result set returned by view.
+   *
+   * The comparison is done on the string representation of the columns of the
+   * column map, taking the order of the rows into account, but not the order
+   * of the columns.
+   *
+   * @param $view
+   *  An executed View.
+   * @param $expected_result
+   *  An expected result set.
+   * @param $column_map
+   *  An associative array mapping the columns of the result set from the view
+   *  (as keys) and the expected result set (as values).
+   */
+  protected function assertIdenticalResultset($view, $expected_result, $column_map = array(), $message = 'Identical result set') {
+    return $this->assertIdenticalResultsetHelper($view, $expected_result, $column_map, $message, 'assertIdentical');
+  }
+
+  /**
+   * Helper function: verify a result set returned by view..
+   *
+   * Inverse of ViewsTestCase::assertIdenticalResultset().
+   *
+   * @param $view
+   *  An executed View.
+   * @param $expected_result
+   *  An expected result set.
+   * @param $column_map
+   *  An associative array mapping the columns of the result set from the view
+   *  (as keys) and the expected result set (as values).
+   */
+  protected function assertNotIdenticalResultset($view, $expected_result, $column_map = array(), $message = 'Identical result set') {
+    return $this->assertIdenticalResultsetHelper($view, $expected_result, $column_map, $message, 'assertNotIdentical');
+  }
+
+  protected function assertIdenticalResultsetHelper($view, $expected_result, $column_map, $message, $assert_method) {
+    // Convert $view->result to an array of arrays.
+    $result = array();
+    foreach ($view->result as $key => $value) {
+      $row = array();
+      foreach ($column_map as $view_column => $expected_column) {
+        // The comparison will be done on the string representation of the value.
+        $row[$expected_column] = (string) $value->$view_column;
+      }
+      $result[$key] = $row;
+    }
+
+    // Remove the columns we don't need from the expected result.
+    foreach ($expected_result as $key => $value) {
+      $row = array();
+      foreach ($column_map as $expected_column) {
+        // The comparison will be done on the string representation of the value.
+        $row[$expected_column] = (string) (is_object($value) ? $value->$expected_column : $value[$expected_column]);
+      }
+      $expected_result[$key] = $row;
+    }
+
+    // Reset the numbering of the arrays.
+    $result = array_values($result);
+    $expected_result = array_values($expected_result);
+
+    $this->verbose('<pre>Returned data set: ' . print_r($result, TRUE) . "\n\nExpected: ". print_r($expected_result, TRUE));
+
+    // Do the actual comparison.
+    return $this->$assert_method($result, $expected_result, $message);
+  }
+}
diff --git a/views/similarterms.views.inc b/views/similarterms.views.inc
index f1d294d..8093fc4 100644
--- a/views/similarterms.views.inc
+++ b/views/similarterms.views.inc
@@ -30,11 +30,9 @@ function similarterms_views_data() {
   $data['similarterms']['nid'] = array(
     'title' => t('Nid'),
     'help' => t('ID of content item(s). Passes term ids to Similar By Terms.'), // The help that appears on the UI,
-    
     // Information for accepting a nid as an argument
     'argument' => array(
       'handler' => 'similarterms_handler_argument_node_nid',
-      'parent' => 'views_handler_argument_numeric', // make sure parent is included
       'name field' => 'title', // the field to display in the summary.
       'numeric' => TRUE,
       'validate type' => 'nid',
@@ -44,25 +42,3 @@ function similarterms_views_data() {
 
   return $data;
 }
-
-/**
- * Implementation of hook_views_handlers().
- */
-function similarterms_views_handlers() {
-  return array(
-    'info' => array(
-      'path' => drupal_get_path('module', 'similarterms') . '/views',
-    ),
-    'handlers' => array(
-      'similarterms_handler_sort_similar' => array(
-        'parent' => 'views_handler_sort',
-      ),
-      'similarterms_handler_argument_node_nid' => array(
-        'parent' => 'views_handler_argument_numeric',
-      ),
-      'similarterms_handler_field_similar' => array(
-        'parent' => 'views_handler_field',
-      ),
-    ),
-  );
-}
diff --git a/views/similarterms_handler_argument_node_nid.inc b/views/similarterms_handler_argument_node_nid.inc
index 76971a3..b922ea8 100644
--- a/views/similarterms_handler_argument_node_nid.inc
+++ b/views/similarterms_handler_argument_node_nid.inc
@@ -1,5 +1,4 @@
 <?php
-// $Id $
 /**
  * @file
  * Provide node nid argument handler.
@@ -8,7 +7,9 @@
 /**
  * Argument handler to accept a node id.
  * based on node_handler_argument_node_nid except that it doesn't
- * add a where clause to the query
+ * add a where clause to the query.
+ *
+ * @ingroup views_argument_handlers
  */
 class similarterms_handler_argument_node_nid extends views_handler_argument_numeric {
   /**
@@ -16,10 +17,9 @@ class similarterms_handler_argument_node_nid extends views_handler_argument_nume
    */
   function title_query() {
     $titles = array();
-    $placeholders = implode(', ', array_fill(0, sizeof($this->value), '%d'));
 
-    $result = db_query("SELECT n.title FROM {node} n WHERE n.nid IN ($placeholders)", $this->value);
-    while ($term = db_fetch_object($result)) {
+    $result = db_query("SELECT n.title FROM {node} n WHERE n.nid IN (:nids)", array(':nids' => $this->value));
+    foreach ($result as $term) {
       $titles[] = check_plain($term->title);
     }
     return $titles;
@@ -39,9 +39,9 @@ class similarterms_handler_argument_node_nid extends views_handler_argument_nume
     
     unset($form['not']);
     
-    $r = db_query('SELECT vid, name FROM {vocabulary} ORDER BY weight');
-    while ($row = db_fetch_object($r)) {
-      $vocabs[$row->vid] = $row->name;
+    $vocabs = taxonomy_get_vocabularies();
+    foreach ($vocabs as $vocab) {
+      $vocabs[$vocab->vid] = $vocab->name;
     }
     
     $form['vocabularies'] = array(
@@ -62,7 +62,7 @@ class similarterms_handler_argument_node_nid extends views_handler_argument_nume
   }
   
   function validate_arg($arg) {
-    
+
     // first run the inherited arg validation
     if (!parent::validate_arg($arg)) {
       return FALSE;
@@ -78,49 +78,29 @@ class similarterms_handler_argument_node_nid extends views_handler_argument_nume
       $this->value = array($this->argument);
     }
         
-    // $vids is array node version ids
-    $vids = array();
-    foreach($this->value as $nid) {
-      // get the current revision id (vid) for this node id (nid)
-      $vids[] = db_result(db_query("SELECT vid FROM {node} WHERE nid = %d", $nid));
-    }
-        
-    // $vocabs is array of vocabulary ids (a.k.a. vids, confusing right?)
+    $nids = $this->value;
+
+  // $vocabs is array of vocabulary ids (a.k.a. vids, confusing right?)
     $vocabs = empty($this->options['vocabularies']) ? array() : $this->options['vocabularies'];
     foreach ($vocabs as $key => $val) {
       if ($val == 0) {
         unset($vocabs[$key]);
       }
     }
-        
-    $addwhere = '';
-    $addjoin = '';
-    if (count($vocabs) == 1) {
-      // we're limiting the terms to those of given vocabs
-      $addjoin = ' INNER JOIN {term_data} td ON tn.tid = td.tid ';
-      $addwhere = " AND td.vid = %d";
-    }
-    elseif (count($vocabs) > 1) {
-      $addjoin = ' INNER JOIN {term_data} td ON tn.tid = td.tid ';
-      $placeholders = implode(', ', array_fill(0, sizeof($vocabs), '%d'));
-      $addwhere = " AND td.vid IN ($placeholders)";
-    }
-    
-    $args = array_merge($vids, $vocabs);
-    if (count($vids) > 1) {
-      $placeholders = implode(', ', array_fill(0, sizeof($vids), '%d'));
-      $result = db_query("SELECT tn.tid FROM {term_node} tn $addjoin WHERE tn.vid IN ($placeholders) $addwhere", $args);
-    }
-    else {
-      $result = db_query("SELECT tn.tid FROM {term_node} tn $addjoin WHERE tn.vid = %d $addwhere", $args);
-    }
-    
-    $tids = array();
-    while ($row = db_fetch_object($result)) {
-      // adding a key to ensure there aren't duplicates
-      $tids[$row->tid] = $row->tid;
+
+    $select = db_select('taxonomy_index', 'ti');
+    // we're limiting the terms to those of given vocabs
+    if ($vocabs) {
+      $select->innerJoin('taxonomy_term_data', 'td', 'ti.tid = td.tid');
+      $select->condition('td.vid', $vocabs);
     }
-    
+
+    $select->addField('ti', 'tid');
+    $select->condition('ti.nid', $nids);
+    $result = $select->execute();
+
+    $tids = $result->fetchCol(0);
+
     $this->tids = $tids;
     $this->view->tids = $tids;
     
@@ -131,37 +111,24 @@ class similarterms_handler_argument_node_nid extends views_handler_argument_nume
     }
     
     return TRUE;
-    
   }
-  
-  
-  function query() {
-  
+
+
+  function query($group_by = FALSE) {
+
     $this->ensure_my_table();
-        
+
     $tids = $this->tids;
-  
-    $v = $this->query->add_table('term_node');
-              
-    if (count($tids) == 1) {
-      $this->query->add_where(0, "term_node.tid = %d", $tids);
-    }
-    elseif (count($tids) > 1) {
-      $placeholders = implode(', ', array_fill(0, count($tids), '%d'));
-      $this->query->add_where(0, "term_node.tid IN ($placeholders)", $tids);
-    }
-          
+
+    $taxonomy_index_alias = $this->query->add_table('taxonomy_index');
+
+    $this->query->add_where(0, "$taxonomy_index_alias.tid", $tids);
+
     // exclude the current node(s)
     if (empty($this->options['include_args'])) {
-      if (count($this->value) > 1) {
-        $placeholders = implode(', ', array_fill(0, count($this->value), '%d'));
-        $this->query->add_where(0, "node.nid NOT IN ($placeholders)", $this->value);
-      }
-      else {
-        $this->query->add_where(0, 'node.nid != %d', $this->value[0]);
-      }
+      $this->query->add_where(0, 'node.nid', $this->value, '<>');
     }
     
   }
   
-}
\ No newline at end of file
+}
diff --git a/views/similarterms_handler_field_similar.inc b/views/similarterms_handler_field_similar.inc
index a5a15d9..67bcbbb 100644
--- a/views/similarterms_handler_field_similar.inc
+++ b/views/similarterms_handler_field_similar.inc
@@ -1,5 +1,10 @@
 <?php
 
+/**
+ * Shows the similarity of the node.
+ *
+ * @ingroup views_field_handlers
+ */
 class similarterms_handler_field_similar extends views_handler_field {
   function option_definition() {
     $options = parent::option_definition();
@@ -30,15 +35,20 @@ class similarterms_handler_field_similar extends views_handler_field {
   }
 
   function query() {
-    // we MIGHT want to ensure that the COUNT data is getting added here.
+    $params = array(
+      'function' => 'count',
+    );
+    $this->field_alias = $this->query->add_field('node', 'nid', NULL, $params);
+
   }
 
   function render($values) {
+    $value = $this->get_value($values);
     if ($this->options['count_type'] == 0) {
-      return $values->node_count;
+      return $value;
     }
     elseif ($this->view->tids) {
-      $output = round($values->node_count/count($this->view->tids) * 100);
+      $output = round($value/count($this->view->tids) * 100);
       if (!empty($this->options['percent_suffix'])) {
         $output .= '%';
       }
@@ -46,4 +56,4 @@ class similarterms_handler_field_similar extends views_handler_field {
     }
     
   }
-}
\ No newline at end of file
+}
diff --git a/views/similarterms_handler_sort_similar.inc b/views/similarterms_handler_sort_similar.inc
index 071f99e..3d48497 100644
--- a/views/similarterms_handler_sort_similar.inc
+++ b/views/similarterms_handler_sort_similar.inc
@@ -1,5 +1,9 @@
 <?php
-
+/**
+ * Handler which sorts the by the similarity.
+ *
+ * @ingroups views_sort_handlers
+ */
 class similarterms_handler_sort_similar extends views_handler_sort {
   
   function option_definition() {
@@ -11,16 +15,13 @@ class similarterms_handler_sort_similar extends views_handler_sort {
   }
 
   function query() {
-      
-    // add function to count nid occurrences based on grouping 
-    $this->query->add_field(NULL, 'COUNT(node.nid)', 'node_count', array('aggregate' => TRUE));
-        
-    // sort 'em
-    $this->query->add_orderby(NULL, NULL, $this->options['order'], 'node_count');
-    
-    // group 'em
-    $this->query->add_groupby('nid');
-        
+    // Check whether it's views3 or views2.
+    $params = array(
+      'function' => 'count',
+    );
+
+    // Add a COUNT(nid) and sort by it.
+    $this->query->add_orderby('node', 'nid', $this->options['order'], NULL, $params);
   }
 
 }
