Repository: scikit-activeml/scikit-activeml (language: python)

Issue:
PWC currently does not check, whethter the provided metric is a callable

PWC currently does not check, whethter the provided metric is a callable



Discussion / hints:

Fix patch:
diff --git a/skactiveml/base.py b/skactiveml/base.py
index 50560621..8de5135d 100644
--- a/skactiveml/base.py
+++ b/skactiveml/base.py
@@ -4,12 +4,12 @@
 import numpy as np
 from sklearn.base import BaseEstimator, ClassifierMixin, clone
 from sklearn.metrics import accuracy_score
-from sklearn.utils import check_array, check_consistent_length, column_or_1d
+from sklearn.utils import check_array, check_consistent_length
 from sklearn.utils.multiclass import type_of_target
 
 from skactiveml.utils import MISSING_LABEL, check_classifier_params, \
     check_random_state, rand_argmin, ExtLabelEncoder, check_cost_matrix, \
-    is_labeled, check_scalar
+    is_labeled, check_scalar, check_class_prior
 
 
 class QueryStrategy(ABC, BaseEstimator):
@@ -307,35 +307,48 @@ def _validate_data(self, X, y, sample_weight):
         # Store and check random state.
         self._random_state = check_random_state(self.random_state)
 
+        # Create label encoder.
+        self._le = ExtLabelEncoder(classes=self.classes,
+                                   missing_label=self.missing_label)
+
         # Check input parameters.
-        X = check_array(X)
+        X = np.array(X)
         y = np.array(y)
         check_consistent_length(X, y)
-        is_lbdl = is_labeled(y, self.missing_label)
-        if len(y[is_lbdl]) > 0:
-            y_type = type_of_target(y[is_lbdl])
-            if y_type not in ['binary', 'multiclass', 'multiclass-multioutput',
-                              'multilabel-indicator', 'multilabel-sequences',
-                              'unknown']:
-                raise ValueError("Unknown label type: %r" % y_type)
-        self._le = ExtLabelEncoder(classes=self.classes,
-                                   missing_label=self.missing_label)
-        y = self._le.fit_transform(y)
-        if len(self._le.classes_) == 0:
-            raise ValueError("No class label is known because 'y' contains no "
-                             "actual class labels and 'classes' is not "
-                             "defined. Change at least on of both to overcome "
-                             "this error.")
-        if sample_weight is not None:
-            sample_weight = np.array(sample_weight)
-            check_consistent_length(y, sample_weight)
-            if y.ndim > 1 and y.shape[1] > 1 or \
-                    sample_weight.ndim > 1 and sample_weight.shape[1] > 1:
-                check_consistent_length(y.T, sample_weight.T)
+        if len(X) > 0:
+            X = check_array(X)
+            is_lbdl = is_labeled(y, self.missing_label)
+            if len(y[is_lbdl]) > 0:
+                y_type = type_of_target(y[is_lbdl])
+                if y_type not in [
+                    'binary', 'multiclass', 'multiclass-multioutput',
+                    'multilabel-indicator', 'multilabel-sequences', 'unknown'
+                ]:
+                    raise ValueError("Unknown label type: %r" % y_type)
+
+            y = self._le.fit_transform(y)
+            if len(self._le.classes_) == 0:
+                raise ValueError(
+                    "No class label is known because 'y' contains no actual "
+                    "class labels and 'classes' is not defined. Change at "
+                    "least on of both to overcome this error."
+                )
+        else:
+            self._le.fit_transform(self.classes)
 
         # Update detected classes.
         self.classes_ = self._le.classes_
 
+        # Check classes.
+        if sample_weight is not None:
+            sample_weight = np.array(sample_weight)
+            if not np.array_equal(y.shape, sample_weight.shape):
+                raise ValueError(
+                    f'`y` has the shape {y.shape} and `sample_weight` has the '
+                    f'shape {sample_weight.shape}. Both need to have identical'
+                    f' shapes.'
+                )
+
         # Update cost matrix.
         self.cost_matrix_ = 1 - np.eye(len(self.classes_)) \
             if self.cost_matrix is None else self.cost_matrix
@@ -347,8 +360,12 @@ def _validate_data(self, X, y, sample_weight):
             self.cost_matrix_ = self.cost_matrix_[:, class_indices]
         return X, y, sample_weight
 
-    def _more_tags(self):
-        return {'multioutput_only': True}
+    def _check_n_features(self, X, reset):
+        if reset:
+            self.n_features_in_ = X.shape[1] if len(X) > 0 else None
+        elif not reset:
+            if self.n_features_in_ is not None:
+                super()._check_n_features(X, reset=reset)
 
 
 class ClassFrequencyEstimator(SkactivemlClassifier):
@@ -382,7 +399,7 @@ class frequencies for given samples (by calling 'predict_freq').
     ----------
     classes_ : np.ndarray, shape (n_classes)
         Holds the label for each class after fitting.
-    class_prior : np.ndarray, shape (n_classes)
+    class_prior_ : np.ndarray, shape (n_classes)
         Prior observations of the class frequency estimates. The entry
         `class_prior_[i]` indicates the non-negative prior number of samples
         belonging to class `classes_[i]`.
@@ -432,23 +449,8 @@ def predict_proba(self, X):
     def _validate_data(self, X, y, sample_weight):
         X, y, sample_weight = super()._validate_data(X, y, sample_weight)
         # Check class prior.
-        if np.isscalar(self.class_prior):
-            check_scalar(self.class_prior, name='class_prior',
-                         target_type=(int, float), min_val=0)
-            class_prior = np.array([self.class_prior] * len(self.classes_))
-        else:
-            class_prior = check_array(self.class_prior, ensure_2d=False)
-            class_prior = column_or_1d(class_prior)
-            if self.classes is None:
-                raise ValueError("You cannot specify 'class_prior' as an "
-                                 "array-like parameter without specifying "
-                                 "'classes'.")
-            is_negative = np.sum(class_prior < 0)
-            if len(class_prior) != len(self.classes_) or is_negative:
-                raise ValueError("`class_prior` must be either a non-negative"
-                                 "float or a list of `n_classes` non-negative "
-                                 "floats.")
-        self.class_prior_ = class_prior.reshape(1, -1)
+        self.class_prior_ = check_class_prior(self.class_prior,
+                                              len(self.classes_))
         return X, y, sample_weight
 
 
diff --git a/skactiveml/classifier/_cmm.py b/skactiveml/classifier/_cmm.py
index b4616e0e..86fd61d7 100644
--- a/skactiveml/classifier/_cmm.py
+++ b/skactiveml/classifier/_cmm.py
@@ -4,15 +4,16 @@
 
 # Author: Marek Herde <marek.herde@uni-kassel.de>
 
-import numpy as np
-
 from copy import deepcopy
+
+import numpy as np
 from scipy.spatial.distance import cdist
 from sklearn.mixture import GaussianMixture, BayesianGaussianMixture
 from sklearn.utils.validation import check_array, \
     check_is_fitted, NotFittedError
-from ..utils import MISSING_LABEL, compute_vote_vectors
+
 from ..base import ClassFrequencyEstimator
+from ..utils import MISSING_LABEL, compute_vote_vectors
 
 
 class CMM(ClassFrequencyEstimator):
@@ -30,7 +31,8 @@ class CMM(ClassFrequencyEstimator):
         will be refitted in each call of the 'fit' method. If None,
         mixture_model=BayesianMixtureModel(n_components=n_classes) will be
         used.
-    weight_mode : {'responsibilities', 'similarities'}
+    weight_mode : {'responsibilities', 'similarities'},
+        default='responsibilities'
         Determines whether the responsibilities outputted by the
         `mixture_model` or the exponentials of the Mahalanobis distances as
         similarities are used to compute the class frequency estimates.
@@ -125,21 +127,24 @@ def fit(self, X, y, sample_weight=None):
                              "or `similarities`, got {} instead."
                              .format(self.weight_mode))
 
-        # Refit model if desired.
-        try:
-            check_is_fitted(self.mixture_model_)
-        except NotFittedError:
-            self.mixture_model_ = self.mixture_model_.fit(X)
+        if self.n_features_in_ is None:
+            self.F_components_ = 0
+        else:
+            # Refit model if desired.
+            try:
+                check_is_fitted(self.mixture_model_)
+            except NotFittedError:
+                self.mixture_model_ = self.mixture_model_.fit(X)
 
-        # Counts number of votes per class label for each sample.
-        V = compute_vote_vectors(y=y, w=sample_weight,
-                                 classes=np.arange(len(self.classes_)))
+            # Counts number of votes per class label for each sample.
+            V = compute_vote_vectors(y=y, w=sample_weight,
+                                     classes=np.arange(len(self.classes_)))
 
-        # Stores responsibility for every given sample of training set.
-        R = self.mixture_model_.predict_proba(X)
+            # Stores responsibility for every given sample of training set.
+            R = self.mixture_model_.predict_proba(X)
 
-        # Stores class frequency estimates per component.
-        self.F_components_ = R.T @ V
+            # Stores class frequency estimates per component.
+            self.F_components_ = R.T @ V
 
         return self
 
diff --git a/skactiveml/classifier/_logistic_regression.py b/skactiveml/classifier/_logistic_regression.py
index 5803c687..b021eac8 100644
--- a/skactiveml/classifier/_logistic_regression.py
+++ b/skactiveml/classifier/_logistic_regression.py
@@ -5,14 +5,13 @@
 # Author: Marek Herde <marek.herde@uni-kassel.de>
 #         Timo Sturm <timo.sturm@student.uni-kassel.de>
 
-import numpy as np
 import warnings
 
+import numpy as np
 from scipy.optimize import minimize
 from scipy.special import softmax
-from scipy.stats import multivariate_normal as multi_normal
 from scipy.stats import dirichlet
-
+from scipy.stats import multivariate_normal as multi_normal
 from sklearn.utils.validation import check_array, check_is_fitted, \
     column_or_1d
 
@@ -151,8 +150,9 @@ def fit(self, X, y, sample_weight=None):
             The LogisticRegressionRY is fitted on the training data.
         """
         # Check input data.
-        X, y, sample_weight = self._validate_data(X=X, y=y,
-                                                   sample_weight=sample_weight)
+        X, y, sample_weight = self._validate_data(
+            X=X, y=y, sample_weight=sample_weight
+        )
         self._check_n_features(X, reset=True)
 
         # Ensure value of 'tol' to be positive.
@@ -170,16 +170,29 @@ def fit(self, X, y, sample_weight=None):
             raise ValueError('`max_iter`= {}, must be an integer >= 1.'
                              .format(self.tol))
 
-        # Insert bias, if 'fit_intercept' is set to 'True'.
         if not isinstance(self.fit_intercept, bool):
             raise TypeError("'fit_intercept' must be of type 'bool', got {}"
                             .format(type(self.fit_intercept)))
-        if self.fit_intercept:
-            X = np.insert(X, 0, values=1, axis=1)
 
         solver_dict = {'maxiter': 5} if self.solver_dict is None \
             else self.solver_dict
 
+        # Check weights prior.
+        if not isinstance(self.weights_prior, (int, float)):
+            raise TypeError("'weights_prior' must be of a positive 'int' or "
+                            "'float', got {}".format(type(self.weights_prior)))
+        if self.weights_prior < 0:
+            raise ValueError("'weights_prior' must be of a positive 'int' or "
+                             "'float', got {}".format(self.weights_prior))
+
+        # Check for empty training data.
+        if len(X) == 0:
+            return self
+
+        # Insert bias, if 'fit_intercept' is set to 'True'.
+        if self.fit_intercept:
+            X = np.insert(X, 0, values=1, axis=1)
+
         # Ensure class labels to form a 2d array.
         if y.ndim <= 1:
             y = y.copy().reshape(-1, 1)
@@ -198,12 +211,6 @@ def fit(self, X, y, sample_weight=None):
         I = np.eye(n_classes)
 
         # Convert Gamma to matrix, if it is a number:
-        if not isinstance(self.weights_prior, (int, float)):
-            raise TypeError("'weights_prior' must be of a positive 'int' or "
-                            "'float', got {}".format(type(self.weights_prior)))
-        if self.weights_prior < 0:
-            raise ValueError("'weights_prior' must be of a positive 'int' or "
-                             "'float', got {}".format(self.weights_prior))
         Gamma = self.weights_prior * np.eye(n_features)
         all_zeroes = not np.any(Gamma)
         Gamma_tmp = Gamma if all_zeroes else np.linalg.inv(Gamma)
@@ -388,6 +395,10 @@ def predict_proba(self, X):
         X = check_array(X)
         self._check_n_features(X, reset=False)
 
+        # Prediction without training data.
+        if self.n_features_in_ is None:
+            return np.ones((len(X), len(self.classes_))) / len(self.classes_)
+
         # Check whether a bias feature is missing.
         if self.fit_intercept:
             X = np.insert(X, 0, values=1, axis=1)
@@ -413,9 +424,18 @@ def predict_annot_proba(self, X):
             P_annot[i,l] is the probability, that annotator l provides the
             correct class label for sample X[i].
         """
+        # Prediction without training data.
+        if self.n_features_in_ is None:
+            return np.ones((len(X), 1)) / len(self.classes_)
+
+        # Compute class probabilities.
         P = self.predict_proba(X)
+
+        # Get correctness probabilities for each annotator per class.
         diag_Alpha = np.array([np.diagonal(self._Alpha[j]) for j in
                                range(self._Alpha.shape[0])])
+
+        # Compute correctness probabilities for each annotator per sample.
         P_annot = P @ diag_Alpha.T
         return P_annot
 
diff --git a/skactiveml/classifier/_multi_annot_classifier.py b/skactiveml/classifier/_multi_annot_classifier.py
index 57c6966b..6d8930b5 100644
--- a/skactiveml/classifier/_multi_annot_classifier.py
+++ b/skactiveml/classifier/_multi_annot_classifier.py
@@ -4,14 +4,13 @@
 
 # Author: Marek Herde <marek.herde@uni-kassel.de>
 
-import numpy as np
-
 from copy import deepcopy
 
-from ..base import SkactivemlClassifier
+import numpy as np
 from sklearn.ensemble._base import _BaseHeterogeneousEnsemble
-
 from sklearn.utils.validation import check_array, check_is_fitted
+
+from ..base import SkactivemlClassifier
 from ..utils import MISSING_LABEL, compute_vote_vectors, is_labeled
 
 
@@ -56,6 +55,7 @@ class MultiAnnotClassifier(_BaseHeterogeneousEnsemble, SkactivemlClassifier):
         training data. If an estimator has been set to `'drop'`, it will not
         appear in `estimators_`.
     """
+
     def __init__(self, estimators, voting='hard', classes=None,
                  missing_label=MISSING_LABEL, cost_matrix=None,
                  random_state=None):
@@ -87,13 +87,20 @@ def fit(self, X, y, sample_weight=None):
             The MultiAnnotClassifier is fitted on the training data.
         """
         self._validate_estimators()
-        X, y, sample_weight = self._validate_data(X=X, y=y,
-                                                   sample_weight=sample_weight)
+        X, y, sample_weight = self._validate_data(
+            X=X, y=y, sample_weight=sample_weight
+        )
         if self.voting not in ('soft', 'hard'):
             raise ValueError("Voting must be 'soft' or 'hard'; got (voting={})"
                              .format(self.voting))
         self._check_n_features(X, reset=True)
         self.estimators_ = deepcopy(self.estimators)
+
+        # Check for empty training data.
+        if len(X) == 0:
+            return self
+
+        # Fit each estimator.
         for i, est in enumerate(self.estimators_):
             est[1].set_params(missing_label=np.nan)
             if self.classes is None or est[1].classes is None:
@@ -124,7 +131,9 @@ def predict_proba(self, X):
         check_is_fitted(self)
         X = check_array(X)
         self._check_n_features(X, reset=False)
-        if self.voting == 'hard':
+        if self.n_features_in_ is None:
+            return np.ones((len(X), len(self.classes_))) / len(self.classes_)
+        elif self.voting == 'hard':
             y_pred = np.array(
                 [est.predict(X) for _, est in self.estimators_]).T
             V = compute_vote_vectors(y=y_pred, classes=self.classes_)
@@ -141,23 +150,26 @@ def _validate_estimators(self):
         for name, est in self.estimators:
             if not isinstance(est, SkactivemlClassifier):
                 raise TypeError(
-                    "'{}' is not a 'SkactivemlClassifier'.".format(est))
+                    f"'{est}' is not a 'SkactivemlClassifier'."
+                )
             if self.voting == 'soft' and not hasattr(est, 'predict_proba'):
-                raise ValueError("If 'voting' is soft, each classifier must"
-                                 "implement 'predict_proba' method. However,"
-                                 "{} does not do so.".format(est))
-            error_msg = "{} of 'estimators' has 'missing_label={}' as attribute" \
-                        " being unequal to the given 'missing_label={}' as " \
-                        "parameter.".format(est, est.missing_label,
-                                            self.missing_label)
+                raise ValueError(
+                    f"If 'voting' is soft, each classifier must "
+                    f"implement 'predict_proba' method. However, "
+                    f"{est} does not do so."
+                )
+            error_msg = f"{est} of 'estimators' has 'missing_label=" \
+                        f"{est.missing_label}' as attribute being unequal " \
+                        f"to the given 'missing_label={self.missing_label}' " \
+                        f"as parameter."
             try:
                 if is_labeled([self.missing_label], est.missing_label)[0]:
-                    raise ValueError(error_msg)
+                    raise TypeError(error_msg)
             except TypeError:
-                raise ValueError(error_msg)
-            error_msg = "{} of 'estimators' has 'classes={}' as attribute " \
-                        "being unequal to the given 'classes={}' as " \
-                        "parameter.".format(est, est.classes, self.classes)
+                raise TypeError(error_msg)
+            error_msg = f"{est} of 'estimators' has 'classes={est.classes}' " \
+                        f"as attribute being unequal to the given 'classes=" \
+                        f"{self.classes}' as parameter."
             classes_none = self.classes is None
             est_classes_none = est.classes is None
             if classes_none and not est_classes_none:
@@ -167,13 +179,13 @@ def _validate_estimators(self):
                 raise ValueError(error_msg)
 
     def _validate_data(self, X, y, sample_weight):
-        X, y, sample_weight = SkactivemlClassifier.\
+        X, y, sample_weight = SkactivemlClassifier. \
             _validate_data(self, X=X, y=y, sample_weight=sample_weight)
-        error_msg = "'y' must have shape (n_samples={}, n_estimators={}) but" \
-                    " has shape {}.".format(len(y), len(self.estimators),
-                                            y.shape)
-        if y.ndim <= 1 and len(self.estimators) == 1:
-            y = y.reshape(len(X), len(self.estimators))
-        if y.ndim <= 1 or y.shape[1] != len(self.estimators):
-            raise ValueError(error_msg)
+        error_msg = f"'y' must have shape (n_samples={len(y)}, n_estimators=" \
+                    f"{len(self.estimators)}) but has shape {y.shape}."
+        if len(X) > 0:
+            if y.ndim <= 1 and len(self.estimators) == 1:
+                y = y.reshape(len(X), len(self.estimators))
+            if y.ndim <= 1 or y.shape[1] != len(self.estimators):
+                raise ValueError(error_msg)
         return X, y, sample_weight
diff --git a/skactiveml/classifier/_pwc.py b/skactiveml/classifier/_pwc.py
index e12b31ee..400ffd0a 100644
--- a/skactiveml/classifier/_pwc.py
+++ b/skactiveml/classifier/_pwc.py
@@ -127,8 +127,12 @@ def fit(self, X, y, sample_weight=None):
         self.X_ = X.copy()
 
         # Convert labels to count vectors.
-        self.V_ = compute_vote_vectors(y=y, w=sample_weight,
-                                       classes=np.arange(len(self.classes_)))
+        if self.n_features_in_ is None:
+            self.V_ = 0
+        else:
+            self.V_ = compute_vote_vectors(
+                y=y, w=sample_weight, classes=np.arange(len(self.classes_))
+            )
 
         return self
 
@@ -150,6 +154,10 @@ def predict_freq(self, X):
         check_is_fitted(self)
         X = check_array(X)
 
+        # Predict zeros because of missing training data.
+        if np.sum(self.V_) == 0:
+            return np.zeros((len(X), len(self.classes_)))
+
         # Compute kernel (metric) matrix.
         if self.metric == 'precomputed':
             K = np.asarray(X)
diff --git a/skactiveml/classifier/_wrapper.py b/skactiveml/classifier/_wrapper.py
index 11a1322c..8255703b 100644
--- a/skactiveml/classifier/_wrapper.py
+++ b/skactiveml/classifier/_wrapper.py
@@ -30,8 +30,7 @@ class SklearnClassifier(SkactivemlClassifier, MetaEstimatorMixin):
     Parameters
     ----------
     estimator : sklearn.base.ClassifierMixin with 'predict_proba' method
-        annot_prior scikit-learn classifier that is to deal with missing
-        labels.
+        scikit-learn classifier that is to deal with missing labels.
     classes : array-like, shape (n_classes), default=None
         Holds the label for each class. If none, the classes are determined
         during the fit.
diff --git a/skactiveml/utils/__init__.py b/skactiveml/utils/__init__.py
index 4528dacb..d60401df 100644
--- a/skactiveml/utils/__init__.py
+++ b/skactiveml/utils/__init__.py
@@ -1,18 +1,18 @@
 """
 The :mod:`skactiveml.utils` module includes various utilities.
 """
-from ._validation import check_classes, check_missing_label, check_scalar,\
-    check_cost_matrix, check_classifier_params, check_X_y, MISSING_LABEL,\
-    check_random_state
 from ._aggregation import compute_vote_vectors
 from ._functions import call_func, simple_batch
 from ._label import is_unlabeled, is_labeled, ExtLabelEncoder
-from ._selection import rand_argmax, rand_argmin
 from ._multi_annot import ext_confusion_matrix
+from ._selection import rand_argmax, rand_argmin
+from ._validation import check_classes, check_missing_label, check_scalar, \
+    check_cost_matrix, check_classifier_params, check_X_y, MISSING_LABEL, \
+    check_random_state, check_class_prior
 
 __all__ = ['rand_argmax', 'rand_argmin', 'compute_vote_vectors',
            'is_unlabeled', 'is_labeled', 'ExtLabelEncoder', 'check_classes',
            'check_missing_label', 'check_cost_matrix', 'check_scalar',
            'check_classifier_params', 'check_X_y', 'check_random_state',
-           'MISSING_LABEL', 'call_func', 'simple_batch',
+           'MISSING_LABEL', 'call_func', 'simple_batch', 'check_class_prior',
            'ext_confusion_matrix']
diff --git a/skactiveml/utils/_functions.py b/skactiveml/utils/_functions.py
index b55319a8..65ecc022 100644
--- a/skactiveml/utils/_functions.py
+++ b/skactiveml/utils/_functions.py
@@ -2,9 +2,10 @@
 import warnings
 
 import numpy as np
+from sklearn.utils.validation import check_array
 
-from skactiveml.utils._selection import rand_argmax
-from skactiveml.utils._validation import check_scalar, check_array
+from ._selection import rand_argmax
+from ._validation import check_scalar
 
 
 def call_func(f_callable, only_mandatory=False, **kwargs):
@@ -34,6 +35,7 @@ def call_func(f_callable, only_mandatory=False, **kwargs):
 
     return f_callable(**vars)
 
+
 def simple_batch(
         utilities, random_state, batch_size=1, return_utilities=False):
     """Generates a batch by selecting the highest values in the 'utilities'.
diff --git a/skactiveml/utils/_multi_annot.py b/skactiveml/utils/_multi_annot.py
index 17e7f675..32da6117 100644
--- a/skactiveml/utils/_multi_annot.py
+++ b/skactiveml/utils/_multi_annot.py
@@ -1,9 +1,9 @@
 import numpy as np
-
-from ..utils import MISSING_LABEL, ExtLabelEncoder
+from sklearn.metrics import confusion_matrix
 from sklearn.utils.validation import check_consistent_length, column_or_1d, \
     check_array
-from sklearn.metrics import confusion_matrix
+
+from ._label import MISSING_LABEL, ExtLabelEncoder
 
 
 def ext_confusion_matrix(y_true, y_pred, classes=None,
diff --git a/skactiveml/utils/_selection.py b/skactiveml/utils/_selection.py
index 32c58f1d..d79e9652 100644
--- a/skactiveml/utils/_selection.py
+++ b/skactiveml/utils/_selection.py
@@ -2,7 +2,7 @@
 
 import numpy as np
 
-from skactiveml.utils import check_random_state
+from ._validation import check_random_state
 
 
 def rand_argmin(a, random_state=None, **argmin_kwargs):


Test patch:
diff --git a/skactiveml/classifier/tests/test_classifier.py b/skactiveml/classifier/tests/test_classifier.py
index 38bf7522..3e1c8621 100644
--- a/skactiveml/classifier/tests/test_classifier.py
+++ b/skactiveml/classifier/tests/test_classifier.py
@@ -1,10 +1,14 @@
+import inspect
 import unittest
 from copy import deepcopy
+from importlib import import_module
+from os import path
 
 import numpy as np
 from sklearn.datasets import make_blobs
 from sklearn.naive_bayes import GaussianNB
 from sklearn.preprocessing import StandardScaler
+from sklearn.utils.validation import NotFittedError
 
 from skactiveml import classifier
 from skactiveml.utils import call_func
@@ -12,7 +16,12 @@
 
 class TestClassifier(unittest.TestCase):
 
-    def test_classifiers(self):
+    def setUp(self):
+        # Build dictionary of attributes.
+        self.classifiers = {}
+        for clf in classifier.__all__:
+            self.classifiers[clf] = getattr(classifier, clf)
+
         # Create data set for testing.
         self.X, self.y_true = make_blobs(random_state=0)
         self.X = StandardScaler().fit_transform(self.X)
@@ -23,24 +32,21 @@ def test_classifiers(self):
         self.y[:100, 0] = self.missing_label
         self.y[200:, 1] = self.missing_label
         self.y_missing_label = np.full_like(self.y, self.missing_label)
+
+        # Set up estimators for Sklearn wrapper and multi-annot classifier.
         self.estimator = GaussianNB()
         cmm = classifier.CMM(missing_label=self.missing_label, random_state=0)
         gnb = classifier.SklearnClassifier(GaussianNB(),
                                            missing_label=self.missing_label)
         self.estimators = [('CMM', cmm), ('GaussianNB', gnb)]
 
-        # Build dictionary of attributes.
-        self.classifiers = {}
-        for clf in classifier.__all__:
-            self.classifiers[clf] = getattr(classifier, clf)
-
+    def test_classifiers(self):
         # Test predictions of classifiers.
         for clf in self.classifiers:
-            print(clf)
-            self._test_classifier(clf)
+            self._test_single_classifier(clf)
 
-    def _test_classifier(self, clf):
-        # Test classifier without fitting.
+    def _test_single_classifier(self, clf):
+        # Create fully initialized classifier.
         clf_mdl = call_func(self.classifiers[clf],
                             estimator=self.estimator,
                             estimators=self.estimators,
@@ -48,42 +54,355 @@ def _test_classifier(self, clf):
                             missing_label=self.missing_label,
                             voting='soft',
                             random_state=0)
-        clf_mdl_copy = deepcopy(clf_mdl)
-        clf_mdl_copy.classes = None
-        if isinstance(clf_mdl_copy, classifier.MultiAnnotClassifier):
-            clf_mdl_copy.estimators = [clf_mdl_copy.estimators[1]]
-        self.assertRaises(ValueError, clf_mdl.fit, X=[], y=[])
-        clf_mdl.fit(X=self.X, y=self.y_missing_label)
-        score = clf_mdl.score(self.X, self.y_true)
-        self.assertTrue(score > 0)
-        if hasattr(clf_mdl, 'predict_proba'):
+
+        # Create classifier without classes parameter.
+        clf_mdl_cls = deepcopy(clf_mdl)
+        clf_mdl_cls.classes = None
+        if isinstance(clf_mdl_cls, classifier.MultiAnnotClassifier):
+            clf_mdl_cls.estimators = [clf_mdl_cls.estimators[1]]
+
+        # Test classifier without fitting.
+        with self.subTest(msg="Not Fitted Test", clf_name=clf):
+            self.assertRaises(NotFittedError, clf_mdl_cls.predict, X=self.X)
+            self.assertRaises(NotFittedError, clf_mdl.predict, X=self.X)
+
+        # Test classifier on empty data set.
+        with self.subTest(msg="Empty Data Test", clf_name=clf):
+            self.assertRaises(ValueError, clf_mdl_cls.predict, X=self.X)
+            clf_mdl.fit(X=[], y=[])
+            P = clf_mdl.predict_proba(X=self.X)
+            np.testing.assert_array_equal(P, np.ones((len(self.X), 3)) / 3)
+            if hasattr(clf_mdl, 'predict_annot_proba'):
+                P = clf_mdl.predict_annot_proba(X=self.X)
+                np.testing.assert_array_equal(P, np.ones((len(self.X), 1)) / 3)
+
+        # Test classifier on data with only missing labels.
+        with self.subTest(msg="Missing Label Test", clf_name=clf):
+            self.assertRaises(ValueError, clf_mdl_cls.fit, X=self.X,
+                              y=self.y_missing_label)
+            clf_mdl.fit(X=self.X, y=self.y_missing_label)
+            score = clf_mdl.score(self.X, self.y_true)
+            self.assertTrue(score > 0)
             P_exp = np.ones((len(self.X), len(self.classes))) \
                     / len(self.classes)
             P = clf_mdl.predict_proba(self.X)
             np.testing.assert_array_equal(P_exp, P)
-        if hasattr(clf_mdl, 'predict_freq'):
-            F_exp = np.zeros((len(self.X), len(self.classes)))
-            F = clf_mdl.predict_freq(self.X)
-            np.testing.assert_array_equal(F_exp, F)
-
-        # Test classifier after fitting.
-        print(clf_mdl.fit(self.X, self.y).score(self.X, self.y_true))
-        self.assertTrue(
-            clf_mdl.fit(self.X, self.y).score(self.X, self.y_true) > 0.8)
-        if hasattr(clf_mdl, 'predict_proba'):
-            P = clf_mdl.predict_proba(self.X)
-            self.assertTrue(np.sum(P != 1 / len(self.classes)) > 0)
-        if hasattr(clf_mdl, 'predict_freq'):
-            F = clf_mdl.predict_freq(self.X)
-            self.assertTrue(np.sum(F) > 0)
+            if hasattr(clf_mdl, 'predict_freq'):
+                F_exp = np.zeros((len(self.X), len(self.classes)))
+                F = clf_mdl.predict_freq(self.X)
+                np.testing.assert_array_equal(F_exp, F)
 
-        # Training on data with only missing labels.
-        clf_mdl = call_func(self.classifiers[clf],
-                            estimator=self.estimator,
-                            estimators=self.estimators,
-                            classes=self.classes,
-                            missing_label=self.missing_label,
-                            voting='soft',
-                            random_state=0)
-        clf_mdl.fit(X=self.X, y=self.y_missing_label)
-        self.assertEqual(clf_mdl.score(self.X, self.y_true), score)
+        # Test classifier on full data set.
+        with self.subTest(msg="Full Data Test", clf_name=clf):
+            score = clf_mdl.fit(self.X, self.y).score(self.X, self.y_true)
+            self.assertTrue(score > 0.8)
+            if hasattr(clf_mdl, 'predict_proba'):
+                P = clf_mdl.predict_proba(self.X)
+                self.assertTrue(np.sum(P != 1 / len(self.classes)) > 0)
+            if hasattr(clf_mdl, 'predict_freq'):
+                F = clf_mdl.predict_freq(self.X)
+                self.assertTrue(np.sum(F) > 0)
+
+    def test_param(self):
+        not_test = ['self', 'kwargs', 'classes', 'X', 'y', 'sample_weight',
+                    'missing_label', 'random_state', 'cost_matrix',
+                    'class_prior']
+        for clf in self.classifiers:
+            with self.subTest(msg=f"Parameter/Method Test", clf=clf):
+                # Get initial parameters.
+                clf_class = self.classifiers[clf]
+                init_params = inspect.signature(clf_class).parameters.keys()
+                init_params = list(init_params)
+
+                # Check initial parameters.
+                values = [Dummy() for i in range(len(init_params))]
+                clf_mdl = clf_class(*values)
+                for param, value in zip(init_params, values):
+                    self.assertTrue(
+                        hasattr(clf_mdl, param),
+                        msg='"{}" not tested for __init__().'.format(param))
+                    self.assertEqual(getattr(clf_mdl, param), value)
+
+                # Get test class to check.
+                class_filename = path.basename(inspect.getfile(clf_class))[:-3]
+                mod = 'skactiveml.classifier.tests.test' + class_filename
+                mod = import_module(mod)
+                test_class_name = 'Test' + clf_class.__name__
+                self.assertTrue(hasattr(mod, test_class_name),
+                                msg='{} has no test called {}.'.format(
+                                    clf, test_class_name)
+                                )
+                test_obj = getattr(mod, test_class_name)
+
+                # Check init parameters.
+                for param in np.setdiff1d(init_params, not_test):
+                    test_func_name = 'test_init_param_' + param
+                    msg = f"'{test_func_name}()' missing for parameter " \
+                          f"'{param}' of __init__() from {clf}."
+                    self.assertTrue(hasattr(test_obj, test_func_name), msg)
+
+                methods = ['fit', 'predict', 'predict_proba', 'predict_freq',
+                           'predict_annot_proba']
+                for m in methods:
+                    if not hasattr(clf_mdl, m):
+                        continue
+                    test_func_name = f'test_{m}'
+                    msg = f"'{test_func_name}()' in test of {clf}."
+                    self.assertTrue(hasattr(test_obj, test_func_name), msg)
+
+                # Check standard parameters of __init__ method.
+                self._test_init_param_random_state(clf_class)
+                self._test_init_param_classes(clf_class)
+                self._test_init_param_missing_label(clf_class)
+                self._test_init_param_cost_matrix(clf_class)
+                if hasattr(clf_mdl, 'predict_freq'):
+                    self._test_init_param_class_prior(clf_class)
+
+                # Check standard parameters of fit method.
+                self._test_fit_param_X(clf_class)
+                self._test_fit_param_y(clf_class)
+                fit_params = inspect.signature(clf_class.fit).parameters.keys()
+                fit_params = list(fit_params)
+                if 'sample_weight' in fit_params:
+                    self._test_fit_param_sample_weight(clf_class)
+                self._test_predict_param_X(clf_class)
+                if hasattr(clf_mdl, 'predict_proba'):
+                    self._test_predict_proba_param_X(clf_class)
+                if hasattr(clf_mdl, 'predict_freq'):
+                    self._test_predict_freq_param_X(clf_class)
+                if hasattr(clf_mdl, 'predict_annot_proba'):
+                    self._test_predict_annot_proba_param_X(clf_class)
+
+    def _test_init_param_class_prior(self, clf_class):
+        clf_mdl = call_func(
+            clf_class,
+            estimator=self.estimator,
+            estimators=self.estimators
+        )
+        self.assertEqual(clf_mdl.class_prior, 0)
+        clf_mdl = call_func(
+            clf_class,
+            estimator=self.estimator,
+            estimators=self.estimators,
+            class_prior=2
+        )
+        self.assertEqual(clf_mdl.class_prior, 2)
+        clf_mdl = call_func(
+            clf_class,
+            estimator=self.estimator,
+            estimators=self.estimators,
+            missing_label=self.missing_label,
+            class_prior=-1.0
+        )
+        self.assertRaises(ValueError, clf_mdl.fit, X=self.X, y=self.y)
+        clf_mdl = call_func(
+            clf_class,
+            estimator=self.estimator,
+            estimators=self.estimators,
+            missing_label=self.missing_label,
+            class_prior=['test']
+        )
+        self.assertRaises(ValueError, clf_mdl.fit, X=self.X, y=self.y)
+        clf_mdl = call_func(
+            clf_class,
+            estimator=self.estimator,
+            estimators=self.estimators,
+            missing_label=self.missing_label,
+            class_prior='test'
+        )
+        self.assertRaises(TypeError, clf_mdl.fit, X=self.X, y=self.y)
+
+    def _test_init_param_classes(self, clf_class):
+        clf_mdl = call_func(
+            clf_class,
+            estimator=self.estimator,
+            estimators=self.estimators
+        )
+        self.assertEqual(clf_mdl.classes, None)
+        clf_mdl = call_func(
+            clf_class,
+            estimator=self.estimator,
+            estimators=self.estimators,
+            classes=[0, 1]
+        )
+        np.testing.assert_array_equal(clf_mdl.classes, [0, 1])
+        clf_mdl = call_func(
+            clf_class,
+            estimator=self.estimator,
+            estimators=self.estimators,
+            classes='Test',
+            missing_label=self.missing_label
+        )
+        self.assertRaises(ValueError, clf_mdl.fit, X=self.X, y=self.y)
+        clf_mdl = call_func(
+            clf_class,
+            estimator=self.estimator,
+            estimators=self.estimators, classes=[0, 1],
+            missing_label=self.missing_label
+        )
+        self.assertRaises(ValueError, clf_mdl.fit, X=self.X, y=self.y)
+        clf_mdl = call_func(
+            clf_class,
+            estimator=self.estimator,
+            estimators=self.estimators,
+            classes=[0, 1, self.missing_label],
+            missing_label=self.missing_label
+        )
+        self.assertRaises(TypeError, clf_mdl.fit, X=self.X, y=self.y)
+
+    def _test_init_param_cost_matrix(self, clf_class):
+        clf_mdl = call_func(
+            clf_class,
+            estimator=self.estimator,
+            estimators=self.estimators
+        )
+        self.assertEqual(clf_mdl.cost_matrix, None)
+        clf_mdl = call_func(
+            clf_class,
+            estimator=self.estimator,
+            estimators=self.estimators,
+            cost_matrix=[1, 2],
+            missing_label=self.missing_label,
+            classes=self.classes
+        )
+        np.testing.assert_array_equal(clf_mdl.cost_matrix, [1, 2])
+        clf_mdl = call_func(
+            clf_class,
+            estimator=self.estimator,
+            estimators=self.estimators,
+            cost_matrix=1 - np.eye(2),
+            classes=self.classes,
+            missing_label=self.missing_label
+        )
+        self.assertRaises(ValueError, clf_mdl.fit, X=self.X, y=self.y)
+        clf_mdl = call_func(
+            clf_class,
+            estimator=self.estimator,
+            estimators=self.estimators,
+            cost_matrix=[['2', '5', '3'], ['a', '5', '3'], ['a', '5', '3']],
+            classes=self.classes,
+            missing_label=self.missing_label
+        )
+        self.assertRaises(ValueError, clf_mdl.fit, X=self.X, y=self.y)
+
+    def _test_init_param_missing_label(self, clf_class):
+        clf_mdl = call_func(
+            clf_class,
+            estimator=self.estimator,
+            estimators=self.estimators
+        )
+        self.assertTrue(np.isnan(clf_mdl.missing_label))
+        clf_mdl = call_func(
+            clf_class,
+            estimator=self.estimator,
+            estimators=self.estimators,
+            missing_label='Test'
+        )
+        self.assertTrue(clf_mdl.missing_label, 'Test')
+        self.assertRaises(TypeError, clf_mdl.fit, X=self.X, y=self.y)
+
+    def _test_init_param_random_state(self, clf_class):
+        clf_mdl = call_func(clf_class, estimator=self.estimator,
+                            estimators=self.estimators)
+        self.assertTrue(clf_mdl.random_state is None)
+        clf_mdl = call_func(
+            clf_class,
+            estimator=self.estimator,
+            estimators=self.estimators,
+            random_state='Test',
+            missing_label=self.missing_label
+        )
+        self.assertEqual(clf_mdl.random_state, 'Test')
+        self.assertRaises(ValueError, clf_mdl.fit, X=self.X, y=self.y)
+
+    def _test_fit_param_X(self, clf_class):
+        clf_mdl = call_func(
+            clf_class,
+            estimator=self.estimator,
+            estimators=self.estimators,
+            missing_label=self.missing_label
+        )
+        y = [0, 1]
+        self.assertRaises(ValueError, clf_mdl.fit, X=[0, 1], y=y)
+        self.assertRaises(ValueError, clf_mdl.fit, X=[['Test'], ['Test']], y=y)
+        self.assertRaises(ValueError, clf_mdl.fit, X=[[0], [1], [2]], y=y)
+
+    def _test_fit_param_y(self, clf_class):
+        clf_mdl = call_func(
+            clf_class,
+            estimator=self.estimator,
+            estimators=self.estimators,
+            missing_label=self.missing_label
+        )
+        X = [[0], [1]]
+        self.assertRaises(ValueError, clf_mdl.fit, X=X, y=[0, 1, 2])
+        self.assertRaises(ValueError, clf_mdl.fit, X=X, y=[[0], [1], [2]])
+
+    def _test_fit_param_sample_weight(self, clf_class):
+        clf_mdl = call_func(
+            clf_class,
+            estimator=self.estimator,
+            estimators=self.estimators,
+            missing_label=self.missing_label
+        )
+        X = [[0], [1]]
+        y = [0, 1]
+        self.assertRaises(ValueError, clf_mdl.fit, X=X, y=y,
+                          sample_weight=[0, 1, 1])
+        self.assertRaises(ValueError, clf_mdl.fit, X=X, y=y,
+                          sample_weight=[[1, 1], [1, 1]])
+
+    def _test_predict_param_X(self, clf_class):
+        clf_mdl = call_func(
+            clf_class,
+            estimator=self.estimator,
+            estimators=self.estimators,
+            missing_label=self.missing_label
+        )
+        clf_mdl.fit(X=self.X, y=self.y)
+        self.assertRaises(ValueError, clf_mdl.predict, X=[0, 0])
+        self.assertRaises(ValueError, clf_mdl.predict, X=[[0], [0]])
+        self.assertRaises(ValueError, clf_mdl.predict, X=[['x', 'y']])
+
+    def _test_predict_proba_param_X(self, clf_class):
+        clf_mdl = call_func(
+            clf_class,
+            estimator=self.estimator,
+            estimators=self.estimators,
+            missing_label=self.missing_label
+        )
+        clf_mdl.fit(X=self.X, y=self.y)
+        self.assertRaises(ValueError, clf_mdl.predict_proba, X=[0, 0])
+        self.assertRaises(ValueError, clf_mdl.predict_proba, X=[[0], [0]])
+        self.assertRaises(ValueError, clf_mdl.predict_proba, X=[['x', 'y']])
+
+    def _test_predict_freq_param_X(self, clf_class):
+        clf_mdl = call_func(
+            clf_class,
+            estimator=self.estimator,
+            estimators=self.estimators,
+            missing_label=self.missing_label
+        )
+        clf_mdl.fit(X=self.X, y=self.y)
+        self.assertRaises(ValueError, clf_mdl.predict_freq, X=[0, 0])
+        self.assertRaises(ValueError, clf_mdl.predict_freq, X=[[0], [0]])
+        self.assertRaises(ValueError, clf_mdl.predict_freq, X=[['x', 'y']])
+
+    def _test_predict_annot_proba_param_X(self, clf_class):
+        clf_mdl = call_func(
+            clf_class,
+            estimator=self.estimator,
+            estimators=self.estimators,
+            missing_label=self.missing_label
+        )
+        clf_mdl.fit(X=self.X, y=self.y)
+        self.assertRaises(ValueError, clf_mdl.predict_annot_proba, X=[0, 0])
+        self.assertRaises(ValueError, clf_mdl.predict_annot_proba,
+                          X=[[0], [0]])
+        self.assertRaises(ValueError, clf_mdl.predict_annot_proba,
+                          X=[['x', 'y']])
+
+
+class Dummy:
+    def __init__(self):
+        pass
diff --git a/skactiveml/classifier/tests/test_cmm.py b/skactiveml/classifier/tests/test_cmm.py
index aa2cc342..a1f461d4 100644
--- a/skactiveml/classifier/tests/test_cmm.py
+++ b/skactiveml/classifier/tests/test_cmm.py
@@ -1,9 +1,10 @@
-import numpy as np
 import unittest
 
-from sklearn.utils.validation import NotFittedError, check_is_fitted
-from sklearn.mixture import BayesianGaussianMixture, GaussianMixture
+import numpy as np
 from sklearn.datasets import make_blobs
+from sklearn.mixture import BayesianGaussianMixture, GaussianMixture
+from sklearn.utils.validation import NotFittedError, check_is_fitted
+
 from skactiveml.classifier import CMM
 
 
@@ -15,26 +16,19 @@ def setUp(self):
         self.y_nan = [['nan', 'nan', 'nan'], ['nan', 'nan', 'nan']]
         self.w = [[2, np.nan, 1], [1, 1, 1]]
 
-    def test_init(self):
+    def test_init_param_mixture_model(self):
         cmm = CMM(missing_label=-1)
-        self.assertEqual(cmm.missing_label, -1)
-        self.assertEqual(cmm.classes, None)
         self.assertEqual(cmm.mixture_model, None)
-        self.assertEqual(cmm.random_state, None)
-        self.assertEqual(cmm.cost_matrix, None)
-        self.assertEqual(cmm.class_prior, 0)
-
-    def test_fit(self):
-        cmm = CMM(missing_label='nan', mixture_model="Test")
+        cmm = CMM(missing_label='nan', mixture_model='Test')
         self.assertRaises(TypeError, cmm.fit, X=self.X, y=self.y)
-        cmm = CMM(missing_label='nan', weight_mode="Test")
-        self.assertRaises(ValueError, cmm.fit, X=self.X, y=self.y)
-        cmm = CMM(missing_label='nan', class_prior=-1.0)
-        self.assertRaises(ValueError, cmm.fit, X=self.X, y=self.y)
-        cmm = CMM(missing_label='nan', class_prior=['test'])
+
+    def test_init_param_weight_mode(self):
+        cmm = CMM(missing_label=-1)
+        self.assertEqual(cmm.weight_mode, 'responsibilities')
+        cmm = CMM(missing_label='nan', weight_mode='Test')
         self.assertRaises(ValueError, cmm.fit, X=self.X, y=self.y)
-        cmm = CMM(missing_label='nan', class_prior='test')
-        self.assertRaises(TypeError, cmm.fit, X=self.X, y=self.y)
+
+    def test_fit(self):
         mixture = GaussianMixture(random_state=0, n_components=4)
         cmm = CMM(missing_label='nan', mixture_model=mixture, classes=[1, 2],
                   cost_matrix=1 - np.eye(3))
@@ -52,8 +46,6 @@ def test_fit(self):
         self.assertEqual(cmm.mixture_model, None)
         np.testing.assert_array_equal(['tokyo', 'paris'], cmm.classes)
         mixture = BayesianGaussianMixture(n_components=1).fit(X=self.X)
-        cmm = CMM(mixture_model=mixture)
-        self.assertRaises(ValueError, cmm.fit, X=[], y=[])
         cmm = CMM(mixture_model=mixture,
                   classes=['tokyo', 'paris', 'new york'], missing_label='nan')
         self.assertEqual(None, cmm.cost_matrix)
@@ -81,6 +73,19 @@ def test_predict_freq(self):
         cmm.fit(X=self.X, y=self.y, sample_weight=self.w)
         F = cmm.predict_freq(X=[self.X[0]])
         np.testing.assert_array_equal([[0, 1, 3]], F)
+        X, y = make_blobs(n_samples=200, centers=2)
+        y_nan = np.full_like(y, np.nan, dtype=float)
+        mixture = BayesianGaussianMixture(n_components=5)
+        cmm = CMM(mixture_model=mixture, classes=[0, 1],
+                  weight_mode='similarities')
+        self.assertRaises(NotFittedError, cmm.predict_freq, X=self.X)
+        cmm.fit(X=X, y=y_nan)
+        F = cmm.predict_freq(X=X)
+        np.testing.assert_array_equal(F.shape, [200, 2])
+        self.assertEqual(F.sum(), 0)
+        cmm.fit(X=X, y=y)
+        F = cmm.predict_freq(X=X)
+        self.assertTrue(F.sum() > 0)
 
     def test_predict_proba(self):
         mixture = BayesianGaussianMixture(n_components=1).fit(X=self.X)
@@ -132,11 +137,6 @@ def test_predict(self):
         y = cmm.predict(self.X)
         np.testing.assert_array_equal(['paris', 'paris'], y)
 
-    def test_on_data_set(self):
-        X, y = make_blobs(n_samples=300, random_state=0)
-        pwc = CMM(weight_mode='similarities', random_state=0).fit(X, y)
-        self.assertTrue(pwc.score(X, y) > 0.5)
-
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/skactiveml/classifier/tests/test_logistic_regression.py b/skactiveml/classifier/tests/test_logistic_regression.py
index 853f6d19..f9a01889 100644
--- a/skactiveml/classifier/tests/test_logistic_regression.py
+++ b/skactiveml/classifier/tests/test_logistic_regression.py
@@ -1,10 +1,9 @@
-import numpy as np
 import unittest
 
-from sklearn.utils.validation import NotFittedError, check_is_fitted
-from sklearn.datasets import make_blobs
-from sklearn.preprocessing import StandardScaler
-from skactiveml.classifier._logistic_regression import LogisticRegressionRY
+import numpy as np
+from sklearn.utils.validation import check_is_fitted
+
+from skactiveml.classifier import LogisticRegressionRY
 
 
 class TestLogisticRegressionRY(unittest.TestCase):
@@ -12,52 +11,86 @@ class TestLogisticRegressionRY(unittest.TestCase):
     def setUp(self):
         self.X = np.zeros((2, 1))
         self.y_nan = [['nan', 'nan', 'nan'], ['nan', 'nan', 'nan']]
-        self.y = [['tokyo', 'nan', 'paris'], ['tokyo', 'nan', 'nan']]
-        self.w = [[2, np.nan, 1], [1, 1, 1]]
-
-    def test_init(self):
-        lr = LogisticRegressionRY(tol=1.e-10, solver='CG', annot_prior_full=2,
-                                  solver_dict={'disp': True}, random_state=0,
-                                  annot_prior_diag=1,
-                                  cost_matrix=1 - np.eye(2),
-                                  classes=['tokyo', 'paris'],
-                                  missing_label='nan', fit_intercept=False)
-        self.assertEqual(lr.tol, 1.e-10)
-        self.assertEqual(lr.solver, 'CG')
-        self.assertEqual(lr.solver_dict, {'disp': True})
-        self.assertEqual(lr.random_state, 0)
-        self.assertEqual(lr.annot_prior_full, 2)
-        self.assertEqual(lr.annot_prior_diag, 1)
-        self.assertEqual(lr.missing_label, 'nan')
-        self.assertFalse(lr.fit_intercept)
-        np.testing.assert_array_equal(lr.classes, ['tokyo', 'paris'])
-        self.assertRaises(NotFittedError, check_is_fitted, estimator=lr)
+        self.y = np.array([['tokyo', 'nan', 'paris'], ['tokyo', 'nan', 'nan']])
+        self.w = np.array([[2, np.nan, 1], [1, 1, 1]])
 
-    def test_fit(self):
+    def test_init_param_tol(self):
+        lr = LogisticRegressionRY()
+        self.assertEqual(lr.tol, 1.e-2)
+        lr = LogisticRegressionRY(tol=1.e-10)
+        self.assertEqual(lr.tol, 1.e-10)
         lr = LogisticRegressionRY(tol=[0.1], missing_label='nan')
         self.assertRaises(TypeError, lr.fit, X=self.X, y=self.y)
         lr = LogisticRegressionRY(tol=0.0, missing_label='nan')
         self.assertRaises(ValueError, lr.fit, X=self.X, y=self.y)
+
+    def test_init_param_solver(self):
+        lr = LogisticRegressionRY()
+        self.assertEqual(lr.solver, 'Newton-CG')
+        lr = LogisticRegressionRY(solver='CG')
+        self.assertEqual(lr.solver, 'CG')
+        lr = LogisticRegressionRY(missing_label='nan', solver='Test')
+        self.assertRaises(ValueError, lr.fit, X=self.X, y=self.y)
+
+    def test_init_param_solver_dict(self):
+        lr = LogisticRegressionRY()
+        self.assertEqual(lr.solver_dict, None)
+        lr = LogisticRegressionRY(solver_dict={'verbose': 0})
+        self.assertTrue(isinstance(lr.solver_dict, dict))
+        lr = LogisticRegressionRY(missing_label='nan', solver_dict='Test')
+        self.assertRaises(ValueError, lr.fit, X=self.X, y=self.y)
+
+    def test_init_param_fit_intercept(self):
+        lr = LogisticRegressionRY()
+        self.assertTrue(lr.fit_intercept)
+        lr = LogisticRegressionRY(fit_intercept=False)
+        self.assertFalse(lr.fit_intercept)
+        lr = LogisticRegressionRY(missing_label='nan', fit_intercept='Test')
+        self.assertRaises(TypeError, lr.fit, X=self.X, y=self.y)
+
+    def test_init_param_max_iter(self):
+        lr = LogisticRegressionRY()
+        self.assertEqual(lr.max_iter, 100)
+        lr = LogisticRegressionRY(max_iter=10)
+        self.assertEqual(lr.max_iter, 10)
         lr = LogisticRegressionRY(max_iter=[1], missing_label='nan')
         self.assertRaises(TypeError, lr.fit, X=self.X, y=self.y)
         lr = LogisticRegressionRY(max_iter=0, missing_label='nan')
         self.assertRaises(ValueError, lr.fit, X=self.X, y=self.y)
-        lr = LogisticRegressionRY(fit_intercept='Test', missing_label='nan')
-        self.assertRaises(TypeError, lr.fit, X=self.X, y=self.y)
+
+    def test_init_param_annot_prior_full(self):
+        lr = LogisticRegressionRY()
+        self.assertEqual(lr.annot_prior_full, 1)
+        lr = LogisticRegressionRY(annot_prior_full=2)
+        self.assertEqual(lr.annot_prior_full, 2)
         lr = LogisticRegressionRY(annot_prior_full=0, missing_label='nan')
         self.assertRaises(ValueError, lr.fit, X=self.X, y=self.y)
         lr = LogisticRegressionRY(annot_prior_full=[1, 1],
                                   missing_label='nan')
         self.assertRaises(ValueError, lr.fit, X=self.X, y=self.y)
+
+    def test_init_param_annot_prior_diag(self):
+        lr = LogisticRegressionRY()
+        self.assertEqual(lr.annot_prior_diag, 0)
+        lr = LogisticRegressionRY(annot_prior_diag=2)
+        self.assertEqual(lr.annot_prior_diag, 2)
         lr = LogisticRegressionRY(annot_prior_diag=-0.1, missing_label='nan')
         self.assertRaises(ValueError, lr.fit, X=self.X, y=self.y)
         lr = LogisticRegressionRY(annot_prior_diag=[0, 0, -0.1],
                                   missing_label='nan')
         self.assertRaises(ValueError, lr.fit, X=self.X, y=self.y)
+
+    def test_init_param_weights_prior(self):
+        lr = LogisticRegressionRY()
+        self.assertEqual(lr.weights_prior, 1)
+        lr = LogisticRegressionRY(weights_prior=0)
+        self.assertEqual(lr.annot_prior_diag, 0)
         lr = LogisticRegressionRY(weights_prior=[0, 1], missing_label='nan')
         self.assertRaises(TypeError, lr.fit, X=self.X, y=self.y)
         lr = LogisticRegressionRY(weights_prior=-0.1, missing_label='nan')
         self.assertRaises(ValueError, lr.fit, X=self.X, y=self.y)
+
+    def test_fit(self):
         lr = LogisticRegressionRY(random_state=0, missing_label='nan',
                                   classes=['tokyo', 'paris'],
                                   solver='Nelder-Mead')
@@ -70,6 +103,8 @@ def test_fit(self):
         lr.fit(X=self.X, y=self.y, sample_weight=self.w)
         self.assertTrue(np.abs(lr.Alpha_ - Alpha_exp).sum() > 0)
         self.assertTrue(np.abs(lr.W_ - W_exp).sum() > 0)
+        lr.fit(X=self.X, y=self.y[:, 0], sample_weight=self.w[:, 0])
+        self.assertEqual(len(lr.Alpha_), 1)
 
     def test_predict_proba(self):
         lr = LogisticRegressionRY(random_state=0, missing_label='nan',
@@ -80,6 +115,16 @@ def test_predict_proba(self):
         lr.fit(X=self.X, y=self.y, sample_weight=self.w)
         np.testing.assert_array_equal(np.sum(P, axis=1), np.ones(len(P)))
 
+    def test_predict(self):
+        lr = LogisticRegressionRY(random_state=0, missing_label='nan',
+                                  classes=['tokyo', 'paris'])
+        lr.fit(X=self.X, y=self.y_nan)
+        y_pred = lr.predict(X=self.X)
+        np.testing.assert_array_equal(y_pred, ['tokyo', 'paris'])
+        lr.fit(X=self.X, y=self.y, sample_weight=self.w)
+        y_pred = lr.predict(X=self.X)
+        np.testing.assert_array_equal(y_pred, ['tokyo', 'tokyo'])
+
     def test_predict_annot_proba(self):
         lr = LogisticRegressionRY(random_state=0, missing_label='nan',
                                   classes=['tokyo', 'paris'])
@@ -89,22 +134,3 @@ def test_predict_annot_proba(self):
         lr.fit(X=self.X, y=self.y, sample_weight=self.w)
         self.assertTrue((P_annot <= 1).all())
         self.assertTrue((P_annot >= 0).all())
-
-    def test_on_data_set(self):
-        X, y_true = make_blobs(n_samples=300, random_state=0)
-        X = StandardScaler().fit_transform(X)
-        lr = LogisticRegressionRY(random_state=0, classes=[0, 1, 2])
-        y = np.array([y_true, y_true, y_true, y_true], dtype=float).T
-        y[0:100, 0] = 0
-        y[100:150, 0] = np.nan
-        y[90:150, 1] = 1
-        y[:, 1] = np.nan
-        w = np.ones_like(y)
-        w[:, 1] = -1000
-        lr.fit(X, y, w)
-        self.assertTrue(lr.score(X, y_true) > 0.8)
-        y = np.full_like(y, fill_value=np.nan)
-        lr.fit(X, y)
-        self.assertTrue(lr.score(X, y_true) > 0.2)
-        lr.fit(X, y_true)
-        self.assertTrue(lr.score(X, y_true) > 0.8)
diff --git a/skactiveml/classifier/tests/test_multi_annot_classifier.py b/skactiveml/classifier/tests/test_multi_annot_classifier.py
index ff1fea80..4fd6235a 100644
--- a/skactiveml/classifier/tests/test_multi_annot_classifier.py
+++ b/skactiveml/classifier/tests/test_multi_annot_classifier.py
@@ -1,42 +1,36 @@
-import numpy as np
 import unittest
 
-from skactiveml.classifier import MultiAnnotClassifier, PWC, \
-    SklearnClassifier
-from sklearn.naive_bayes import GaussianNB
-from sklearn.linear_model import Perceptron
+import numpy as np
 from sklearn.datasets import make_blobs
+from sklearn.linear_model import Perceptron
+from sklearn.naive_bayes import GaussianNB
 from sklearn.utils.validation import NotFittedError
 
+from skactiveml.classifier import MultiAnnotClassifier, PWC, \
+    SklearnClassifier
+from skactiveml.utils import MISSING_LABEL
+
 
 class TestMultiAnnotClassifier(unittest.TestCase):
 
     def setUp(self):
-        self.X, self.y = make_blobs(n_samples=300, random_state=0)
-        self.y = np.array([self.y, self.y], dtype=float).T
-        self.y[:100, 0] = np.nan
+        self.X, self.y_true = make_blobs(n_samples=300, random_state=0)
+        self.y = np.array([self.y_true, self.y_true], dtype=float).T
+        self.y[:100, 0] = MISSING_LABEL
 
-    def test_init(self):
-        clf = MultiAnnotClassifier(estimators='Test', missing_label=-1)
-        self.assertEqual(clf.missing_label, -1)
-        self.assertEqual(clf.classes, None)
+    def test_init_param_estimators(self):
+        clf = MultiAnnotClassifier(estimators='Test')
         self.assertEqual(clf.estimators, 'Test')
-        self.assertEqual(clf.voting, 'hard')
-        self.assertEqual(clf.random_state, None)
-        self.assertEqual(clf.cost_matrix, None)
-
-    def test_fit(self):
+        self.assertRaises(ValueError, clf.fit, X=self.X, y=self.y)
         clf = MultiAnnotClassifier(estimators=None)
         self.assertRaises(ValueError, clf.fit, X=self.X, y=self.y)
         clf = MultiAnnotClassifier(estimators=[('GNB', GaussianNB())])
         self.assertRaises(TypeError, clf.fit, X=self.X, y=self.y)
         clf = MultiAnnotClassifier(estimators=[('PWC', PWC(missing_label=0))])
-        self.assertRaises(ValueError, clf.fit, X=self.X, y=self.y)
-        clf = MultiAnnotClassifier(estimators=[('PWC', PWC())], voting='test')
-        self.assertRaises(ValueError, clf.fit, X=self.X, y=self.y[:, 1])
+        self.assertRaises(TypeError, clf.fit, X=self.X, y=self.y)
         clf = MultiAnnotClassifier(estimators=
                                    [('PWC', PWC(missing_label='a'))])
-        self.assertRaises(ValueError, clf.fit, X=self.X, y=self.y)
+        self.assertRaises(TypeError, clf.fit, X=self.X, y=self.y)
         clf = MultiAnnotClassifier(classes=[0, 1],
                                    estimators=[('PWC', PWC(classes=[0, 2]))])
         self.assertRaises(ValueError, clf.fit, X=self.X, y=self.y)
@@ -45,6 +39,17 @@ def test_fit(self):
         perc = SklearnClassifier(Perceptron())
         clf = MultiAnnotClassifier(estimators=[('perc', perc)], voting='soft')
         self.assertRaises(ValueError, clf.fit, X=self.X, y=self.y)
+
+    def test_init_param_voting(self):
+        pwc = PWC()
+        gnb = SklearnClassifier(GaussianNB())
+        estimators = [('pwc', pwc), ('gnb', gnb)]
+        clf = MultiAnnotClassifier(estimators=estimators, voting='Test')
+        self.assertRaises(ValueError, clf.fit, X=self.X, y=self.y)
+        clf = MultiAnnotClassifier(estimators=estimators, voting=1)
+        self.assertRaises(ValueError, clf.fit, X=self.X, y=self.y)
+
+    def test_fit(self):
         pwc = PWC(classes=[1, 2])
         gnb = SklearnClassifier(GaussianNB(), classes=[1, 2])
         clf = MultiAnnotClassifier(estimators=[('PWC', pwc)],
@@ -56,7 +61,11 @@ def test_fit(self):
         clf = MultiAnnotClassifier(estimators=[('PWC', pwc), ('GNB', gnb)],
                                    voting='soft', classes=np.arange(3))
         self.assertRaises(ValueError, clf.fit, X=self.X, y=self.y[:, 0])
-        clf.fit(X=self.X, y=self.y)
+        clf = MultiAnnotClassifier(estimators=[('PWC', pwc)],
+                                   voting='soft', classes=np.arange(3))
+        clf.fit(X=self.X, y=self.y[:, 0],
+                sample_weight=np.ones_like(self.y[:, 0]))
+        self.assertEqual(len(clf.estimators_), 1)
 
     def test_predict_proba(self):
         pwc = PWC()
@@ -72,6 +81,22 @@ def test_predict_proba(self):
         P = clf.predict_proba(X=self.X)
         np.testing.assert_allclose(np.ones(len(P)), P.sum(axis=1))
 
+    def test_predict(self):
+        pwc = PWC(random_state=0)
+        gnb = SklearnClassifier(GaussianNB(), random_state=0)
+        clf = MultiAnnotClassifier(estimators=[('PWC', pwc), ('GNB', gnb)],
+                                   voting='soft', random_state=0)
+        self.assertRaises(NotFittedError, clf.predict, X=self.X)
+        clf.fit(X=self.X, y=self.y)
+        y_pred_soft = clf.predict(X=self.X)
+        self.assertEqual(len(y_pred_soft), len(self.X))
+        self.assertTrue(clf.score(self.X, self.y_true), 0.8)
+        clf.voting = 'hard'
+        clf.fit(X=self.X, y=self.y)
+        y_pred_hard = clf.predict(X=self.X)
+        self.assertEqual(len(y_pred_hard), len(self.X))
+        self.assertTrue(clf.score(self.X, self.y_true), 0.8)
+
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/skactiveml/classifier/tests/test_pwc.py b/skactiveml/classifier/tests/test_pwc.py
index 6d87ce29..5a681314 100644
--- a/skactiveml/classifier/tests/test_pwc.py
+++ b/skactiveml/classifier/tests/test_pwc.py
@@ -1,8 +1,7 @@
 import unittest
 
 import numpy as np
-from sklearn.datasets import make_blobs
-from sklearn.utils.validation import NotFittedError, check_is_fitted
+from sklearn.utils.validation import NotFittedError
 
 from skactiveml.classifier import PWC
 
@@ -15,41 +14,35 @@ def setUp(self):
         self.y = [['tokyo', 'nan', 'paris'], ['tokyo', 'nan', 'nan']]
         self.w = [[2, np.nan, 1], [1, 1, 1]]
 
-    def test_init(self):
+    def test_init_param_metric_dict(self):
         pwc = PWC(missing_label=-1)
-        self.assertEqual(pwc.missing_label, -1)
-        self.assertEqual(pwc.classes, None)
         self.assertEqual(pwc.metric_dict, None)
-        self.assertEqual(pwc.random_state, None)
-        self.assertEqual(pwc.cost_matrix, None)
-        self.assertEqual(pwc.class_prior, 0)
+        pwc = PWC(missing_label='nan', metric_dict='Test')
+        self.assertRaises(TypeError, pwc.fit, X=self.X, y=self.y)
+        pwc = PWC(missing_label='nan', metric_dict=['gamma'])
+        self.assertRaises(TypeError, pwc.fit, X=self.X, y=self.y)
 
-    def test_fit(self):
-        pwc = PWC(missing_label='nan', metric="Test")
+    def test_init_param_metric(self):
+        pwc = PWC()
+        self.assertEqual(pwc.metric, 'rbf')
+        pwc = PWC(metric='Test')
+        self.assertEqual(pwc.metric, 'Test')
+        pwc = PWC(missing_label='nan', metric='Test')
         self.assertRaises(ValueError, pwc.fit, X=self.X, y=self.y)
-        pwc = PWC(missing_label='nan', n_neighbors=-1)
-        self.assertRaises(ValueError, pwc.fit, X=self.X, y=self.y)
-        pwc = PWC(missing_label='nan', n_neighbors=1.0)
-        self.assertRaises(TypeError, pwc.fit, X=self.X, y=self.y)
-        pwc = PWC(missing_label='nan', class_prior=-1.0)
+
+    def test_init_param_n_neighbors(self):
+        pwc = PWC()
+        self.assertTrue(pwc.n_neighbors is None)
+        pwc = PWC(n_neighbors=1)
+        self.assertEqual(pwc.n_neighbors, 1)
+        pwc = PWC(missing_label='nan', n_neighbors=0)
         self.assertRaises(ValueError, pwc.fit, X=self.X, y=self.y)
-        pwc = PWC(missing_label='nan', class_prior=['test'])
+        pwc = PWC(missing_label='nan', n_neighbors=-1)
         self.assertRaises(ValueError, pwc.fit, X=self.X, y=self.y)
-        pwc = PWC(missing_label='nan', class_prior='test')
-        self.assertRaises(TypeError, pwc.fit, X=self.X, y=self.y)
-        pwc = PWC(missing_label='nan', metric_dict=['gamma'])
+        pwc = PWC(missing_label='nan', n_neighbors=1.5)
         self.assertRaises(TypeError, pwc.fit, X=self.X, y=self.y)
-        pwc = PWC(missing_label='nan', cost_matrix=1 - np.eye(3))
-        self.assertRaises(ValueError, pwc.fit, X=self.X, y=self.y)
-        pwc = PWC(missing_label=None)
-        self.assertRaises(NotFittedError, check_is_fitted, estimator=pwc)
-        cost_matrix = 1 - np.eye(2)
-        pwc = PWC(classes=['tokyo', 'paris'], cost_matrix=cost_matrix,
-                  missing_label='nan')
-        np.testing.assert_array_equal(cost_matrix, pwc.cost_matrix)
-        pwc = PWC(missing_label='nan')
-        self.assertRaises(ValueError, pwc.fit, X=[], y=[])
-        self.assertRaises(ValueError,  pwc.fit, X=self.X, y=self.y_nan)
+
+    def test_fit(self):
         pwc = PWC(classes=['tokyo', 'paris', 'new york'], missing_label='nan')
         pwc.fit(X=self.X, y=self.y_nan)
         self.assertIsNone(pwc.cost_matrix)
@@ -106,12 +99,12 @@ def test_predict_proba(self):
                   n_neighbors=1, metric='precomputed', class_prior=1)
         pwc.fit(X=self.X, y=self.y, sample_weight=self.w)
         P = pwc.predict_proba(X=[[1, 0]])
-        np.testing.assert_array_equal([[1/6, 2/6, 3/6]], P)
+        np.testing.assert_array_equal([[1 / 6, 2 / 6, 3 / 6]], P)
         pwc = PWC(classes=['tokyo', 'paris', 'new york'], missing_label='nan',
                   n_neighbors=1, metric='precomputed', class_prior=[0, 0, 1])
         pwc.fit(X=self.X, y=self.y, sample_weight=self.w)
         P = pwc.predict_proba(X=[[1, 0]])
-        np.testing.assert_array_equal([[0, 1/4, 3/4]], P)
+        np.testing.assert_array_equal([[0, 1 / 4, 3 / 4]], P)
 
     def test_predict(self):
         pwc = PWC(classes=['tokyo', 'paris'], missing_label='nan',
@@ -138,11 +131,6 @@ def test_predict(self):
         y = pwc.predict(self.X)
         np.testing.assert_array_equal(['paris', 'paris'], y)
 
-    def test_on_data_set(self):
-        X, y = make_blobs(n_samples=300, random_state=0)
-        pwc = PWC(random_state=0).fit(X, y)
-        self.assertTrue(pwc.score(X, y) > 0.5)
-
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/skactiveml/classifier/tests/test_wrapper.py b/skactiveml/classifier/tests/test_wrapper.py
index 09631bbe..0a26cb62 100644
--- a/skactiveml/classifier/tests/test_wrapper.py
+++ b/skactiveml/classifier/tests/test_wrapper.py
@@ -13,7 +13,7 @@
 from skactiveml.classifier import SklearnClassifier
 
 
-class TestClassifierWrapper(unittest.TestCase):
+class TestSklearnClassifier(unittest.TestCase):
 
     def setUp(self):
         self.X = np.zeros((4, 1))
@@ -22,27 +22,16 @@ def setUp(self):
         self.y_nan = [['nan', 'nan'], ['nan', 'nan'], ['nan', 'nan'],
                       ['nan', 'nan']]
 
-    def test_init(self):
-        clf = SklearnClassifier(estimator=None, missing_label=-1)
-        self.assertEqual(clf.missing_label, -1)
-        self.assertEqual(clf.classes, None)
-        self.assertEqual(clf.estimator, None)
-        self.assertEqual(clf.random_state, None)
-        self.assertEqual(clf.cost_matrix, None)
-
-    def test_fit(self):
-        clf = SklearnClassifier(missing_label='nan', estimator=None)
-        self.assertRaises(TypeError, clf.fit, X=self.X, y=self.y1)
+    def test_init_param_estimator(self):
+        clf = SklearnClassifier(estimator='Test')
+        self.assertEqual(clf.estimator, 'Test')
+        clf = SklearnClassifier(estimator='Test')
+        self.assertEqual(clf.estimator, 'Test')
         clf = SklearnClassifier(missing_label='nan',
                                 estimator=GaussianProcessRegressor())
         self.assertRaises(TypeError, clf.fit, X=self.X, y=self.y1)
-        clf = SklearnClassifier(missing_label=[2],
-                                estimator=GaussianProcessClassifier())
-        self.assertRaises(TypeError, clf.fit, X=self.X, y=self.y1)
-        clf = SklearnClassifier(estimator=GaussianProcessClassifier(),
-                                random_state=0)
-        self.assertFalse(hasattr(clf, 'classes_'))
-        self.assertRaises(NotFittedError, check_is_fitted, estimator=clf)
+
+    def test_fit(self):
         clf = SklearnClassifier(estimator=GaussianProcessClassifier(),
                                 missing_label='nan',
                                 classes=['tokyo', 'paris'], random_state=0)
@@ -50,12 +39,11 @@ def test_fit(self):
         self.assertEqual(clf.kernel, clf.estimator.kernel)
         self.assertFalse(hasattr(clf, 'kernel_'))
         clf = SklearnClassifier(estimator=Perceptron(),
-                               missing_label='nan', cost_matrix=1 - np.eye(2),
-                               classes=['tokyo', 'paris'], random_state=0)
+                                missing_label='nan', cost_matrix=1 - np.eye(2),
+                                classes=['tokyo', 'paris'], random_state=0)
         self.assertRaises(ValueError, clf.fit, X=self.X, y=self.y1)
         clf = SklearnClassifier(estimator=GaussianProcessClassifier())
         self.assertRaises(NotFittedError, check_is_fitted, estimator=clf)
-        self.assertRaises(ValueError, clf.fit, X=[], y=[])
         clf = SklearnClassifier(estimator=GaussianProcessClassifier(),
                                 classes=['tokyo', 'paris', 'new york'],
                                 missing_label='nan')
@@ -82,8 +70,6 @@ def test_fit(self):
         self.assertTrue(ensemble.is_fitted_, True)
 
     def test_partial_fit(self):
-        clf = SklearnClassifier(estimator=GaussianNB())
-        self.assertRaises(ValueError, clf.partial_fit, X=[], y=[])
         clf = SklearnClassifier(estimator=GaussianNB(),
                                 classes=['tokyo', 'paris', 'new york'],
                                 missing_label='nan')
diff --git a/skactiveml/pool/tests/test_four_ds.py b/skactiveml/pool/tests/test_four_ds.py
index d294ffb0..06704f25 100644
--- a/skactiveml/pool/tests/test_four_ds.py
+++ b/skactiveml/pool/tests/test_four_ds.py
@@ -1,13 +1,14 @@
-import numpy as np
 import unittest
 
-from skactiveml.pool import FourDS
-from skactiveml.classifier import CMM, SklearnClassifier
+import numpy as np
+from sklearn.datasets import load_breast_cancer
 from sklearn.gaussian_process import GaussianProcessClassifier
 from sklearn.mixture import BayesianGaussianMixture
-from sklearn.datasets import load_breast_cancer
 from sklearn.preprocessing import StandardScaler
 
+from skactiveml.classifier import CMM, SklearnClassifier
+from skactiveml.pool import FourDS
+
 
 class TestFourDS(unittest.TestCase):
 
@@ -83,7 +84,7 @@ def test_query_param_sample_weight(self):
         al4ds = FourDS(clf=CMM())
         self.assertRaises(ValueError, al4ds.query, X=self.X, X_cand=self.X,
                           y=self.y, sample_weight=np.ones(1))
-        self.assertRaises(TypeError, al4ds.query, X=self.X, X_cand=self.X,
+        self.assertRaises(ValueError, al4ds.query, X=self.X, X_cand=self.X,
                           y=self.y, sample_weight='test')
 
     def test_query(self):
diff --git a/skactiveml/pool/tests/test_probal.py b/skactiveml/pool/tests/test_probal.py
index a70902d4..c8feb3ce 100644
--- a/skactiveml/pool/tests/test_probal.py
+++ b/skactiveml/pool/tests/test_probal.py
@@ -65,7 +65,7 @@ def test_query_param_y(self):
 
     def test_query_param_sample_weight(self):
         pal = McPAL(self.clf)
-        self.assertRaises(TypeError, pal.query, X_cand=self.X_cand,
+        self.assertRaises(ValueError, pal.query, X_cand=self.X_cand,
                           X=self.X, y=self.y, sample_weight='string')
         self.assertRaises(ValueError, pal.query, X_cand=self.X_cand,
                           X=self.X, y=self.y, sample_weight=np.ones(3))
diff --git a/skactiveml/pool/tests/test_qbc.py b/skactiveml/pool/tests/test_qbc.py
index aaefb2f5..44d6aafc 100644
--- a/skactiveml/pool/tests/test_qbc.py
+++ b/skactiveml/pool/tests/test_qbc.py
@@ -1,16 +1,14 @@
-import numpy as np
 import unittest
 
-from sklearn.datasets import make_blobs
+import numpy as np
+from sklearn.ensemble import BaggingClassifier
 from sklearn.ensemble import RandomForestClassifier
 from sklearn.gaussian_process import GaussianProcessRegressor, \
     GaussianProcessClassifier
-from sklearn.ensemble import BaggingClassifier
 
-from skactiveml.base import SkactivemlClassifier
 from skactiveml.classifier import PWC, SklearnClassifier
-from skactiveml.utils import MISSING_LABEL
 from skactiveml.pool._qbc import QBC, average_kl_divergence, vote_entropy
+from skactiveml.utils import MISSING_LABEL
 
 
 class TestQBC(unittest.TestCase):
@@ -82,9 +80,9 @@ def test_query_param_X_cand(self):
 
     def test_query_param_X(self):
         selector = QBC(clf=self.clf)
-        self.assertRaises(ValueError, selector.query, X_cand=self.X_cand,
+        self.assertRaises(TypeError, selector.query, X_cand=self.X_cand,
                           X=None, y=self.y)
-        self.assertRaises(ValueError, selector.query, X_cand=self.X_cand,
+        self.assertRaises(TypeError, selector.query, X_cand=self.X_cand,
                           X='string', y=self.y)
         self.assertRaises(ValueError, selector.query, X_cand=self.X_cand,
                           X=[], y=self.y)
@@ -104,7 +102,7 @@ def test_query_param_y(self):
 
     def test_query_param_sample_weight(self):
         selector = QBC(clf=self.clf)
-        self.assertRaises(TypeError, selector.query, **self.kwargs,
+        self.assertRaises(ValueError, selector.query, **self.kwargs,
                           sample_weight='string')
         self.assertRaises(ValueError, selector.query, **self.kwargs,
                           sample_weight=self.X_cand)
diff --git a/skactiveml/pool/tests/test_uncertainty.py b/skactiveml/pool/tests/test_uncertainty.py
index 8f33b534..3012d6ea 100644
--- a/skactiveml/pool/tests/test_uncertainty.py
+++ b/skactiveml/pool/tests/test_uncertainty.py
@@ -1,12 +1,12 @@
-import numpy as np
 import unittest
 
+import numpy as np
 from sklearn.gaussian_process import GaussianProcessClassifier
 
-from skactiveml.pool._uncertainty import uncertainty_scores
-from skactiveml.utils import MISSING_LABEL
 from skactiveml.classifier import SklearnClassifier, PWC
 from skactiveml.pool import UncertaintySampling, expected_average_precision
+from skactiveml.pool._uncertainty import uncertainty_scores
+from skactiveml.utils import MISSING_LABEL
 
 
 class TestUncertaintySampling(unittest.TestCase):
@@ -78,9 +78,9 @@ def test_query_param_X_cand(self):
 
     def test_query_param_X(self):
         selector = UncertaintySampling(clf=self.clf)
-        self.assertRaises(ValueError, selector.query, X_cand=self.X_cand,
+        self.assertRaises(TypeError, selector.query, X_cand=self.X_cand,
                           X=None, y=self.y)
-        self.assertRaises(ValueError, selector.query, X_cand=self.X_cand,
+        self.assertRaises(TypeError, selector.query, X_cand=self.X_cand,
                           X='string', y=self.y)
         self.assertRaises(ValueError, selector.query, X_cand=self.X_cand,
                           X=[], y=self.y)
@@ -100,7 +100,7 @@ def test_query_param_y(self):
 
     def test_query_param_sample_weight(self):
         selector = UncertaintySampling(clf=self.clf)
-        self.assertRaises(TypeError, selector.query, **self.kwargs,
+        self.assertRaises(ValueError, selector.query, **self.kwargs,
                           sample_weight='string')
         self.assertRaises(ValueError, selector.query, **self.kwargs,
                           sample_weight=self.X_cand)
diff --git a/skactiveml/utils/tests/test_functions.py b/skactiveml/utils/tests/test_functions.py
index 135c4f96..6945b593 100644
--- a/skactiveml/utils/tests/test_functions.py
+++ b/skactiveml/utils/tests/test_functions.py
@@ -1,7 +1,8 @@
 import unittest
+
 import numpy as np
 
-from skactiveml.utils import simple_batch
+from skactiveml.utils import simple_batch, call_func
 
 
 class TestFunctions(unittest.TestCase):
@@ -28,12 +29,25 @@ def test_simple_batch(self):
                                         return_utilities=True)
         np.testing.assert_array_equal(indices, expected_indices)
         np.testing.assert_array_equal(batches, expected_batches)
+        indices = simple_batch(utils, random_state=42,
+                               batch_size='adaptive',
+                               return_utilities=False)
+        np.testing.assert_array_equal(indices, expected_indices[:1])
 
         indices, batches = simple_batch(utils, random_state=42, batch_size=3,
                                         return_utilities=True)
         np.testing.assert_array_equal(indices[0:3], expected_indices[0:3])
         np.testing.assert_array_equal(batches[0:3], expected_batches[0:3])
 
+    def test_call_func(self):
+        def dummy_function(a, b=2, c=3):
+            return a * b * c
+
+        result = call_func(dummy_function, a=2, b=5, c=5)
+        self.assertEqual(result, 50)
+        result = call_func(dummy_function, only_mandatory=True, a=2, b=5, c=5)
+        self.assertEqual(result, 12)
+
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/skactiveml/utils/tests/test_validation.py b/skactiveml/utils/tests/test_validation.py
index a3aff901..9f41911f 100644
--- a/skactiveml/utils/tests/test_validation.py
+++ b/skactiveml/utils/tests/test_validation.py
@@ -1,10 +1,11 @@
 import unittest
-import numpy as np
 import warnings
 
+import numpy as np
+
 from skactiveml.utils import check_cost_matrix, check_classes, \
     check_missing_label, check_scalar, check_X_y
-from skactiveml.utils._validation import check_random_state, check_class_prior
+from skactiveml.utils import check_random_state, check_class_prior
 
 
 class TestValidation(unittest.TestCase):