diff --git a/apps/wei/forms/surveys/base.py b/apps/wei/forms/surveys/base.py
index ec0bc980eb7f4f6e786bc26776263e51c8aad7ff..030f907832487f2ae5c6b9d8ce7431860372cafb 100644
--- a/apps/wei/forms/surveys/base.py
+++ b/apps/wei/forms/surveys/base.py
@@ -53,7 +53,8 @@ class WEIBusInformation:
     def free_seats(self, surveys: List["WEISurvey"] = None):
         size = self.bus.size
         already_occupied = WEIMembership.objects.filter(bus=self.bus).count()
-        valid_surveys = sum(1 for survey in surveys if survey.information.valid) if surveys else 0
+        valid_surveys = sum(1 for survey in surveys if survey.information.valid
+                            and survey.information.get_selected_bus() == self.bus) if surveys else 0
         return size - already_occupied - valid_surveys
 
     def has_free_seats(self, surveys=None):
diff --git a/apps/wei/forms/surveys/wei2021.py b/apps/wei/forms/surveys/wei2021.py
index 49c1c628212f4bee02425f6c2d97fe860d694a2c..8d5adfadd1c64a4e44ce1acf2bc04c4502380d29 100644
--- a/apps/wei/forms/surveys/wei2021.py
+++ b/apps/wei/forms/surveys/wei2021.py
@@ -16,7 +16,7 @@ WORDS = [
     'Fanfare', 'Fracassage', 'Féria', 'Hard rock', 'Hoeggarden', 'House', 'Huit-six', 'IPA', 'Inclusif', 'Inferno',
     'Introverti', 'Jager bomb', 'Jazz', 'Jeux d\'alcool', 'Jeux de rôles', 'Jeux vidéo', 'Jul', 'Jus de fruit',
     'Karaoké', 'LGBTQI+', 'Lady Gaga', 'Loup garou', 'Morning beer', 'Métal', 'Nuit blanche', 'Ovalie', 'Psychedelic',
-    'Pétanque',  'Rave', 'Reggae', 'Rhum', 'Ricard', 'Rock', 'Rosé', 'Rétro', 'Séducteur', 'Techno', 'Thérapie taxi',
+    'Pétanque', 'Rave', 'Reggae', 'Rhum', 'Ricard', 'Rock', 'Rosé', 'Rétro', 'Séducteur', 'Techno', 'Thérapie taxi',
     'Théâtre', 'Trap', 'Turn up', 'Underground', 'Volley', 'Wati B', 'Zinédine Zidane',
 ]
 
@@ -45,9 +45,9 @@ class WEISurveyForm2021(forms.Form):
         rng = Random(information.seed)
 
         words = []
-        for _ in range(information.step + 1):
+        for _ignored in range(information.step + 1):
             # Generate N times words
-            words = [rng.choice(WORDS) for _ in range(10)]
+            words = [rng.choice(WORDS) for _ignored2 in range(10)]
         words = [(w, w) for w in words]
         if self.data:
             self.fields["word"].choices = [(w, w) for w in WORDS]
@@ -162,7 +162,7 @@ class WEISurveyAlgorithm2021(WEISurveyAlgorithm):
         while free_surveys:  # Some students are not affected
             survey = free_surveys[0]
             buses = survey.ordered_buses()  # Preferences of the student
-            for bus, _ in buses:
+            for bus, _ignored in buses:
                 if self.get_bus_information(bus).has_free_seats(surveys):
                     # Selected bus has free places. Put student in the bus
                     survey.select_bus(bus)
@@ -190,6 +190,9 @@ class WEISurveyAlgorithm2021(WEISurveyAlgorithm):
                         # If it does not exist, choose the next bus.
                         least_preferred_survey.free()
                         least_preferred_survey.save()
+                        free_surveys.append(least_preferred_survey)
                         survey.select_bus(bus)
                         survey.save()
                         break
+            else:
+                raise ValueError(f"User {survey.registration.user} has no free seat")
diff --git a/apps/wei/management/commands/wei_algorithm.py b/apps/wei/management/commands/wei_algorithm.py
index 152ca813f4f18a6a9879658620ed99985f27a2e2..558dfae4f10d0104312ac9ace8a5ee284a3d8d62 100644
--- a/apps/wei/management/commands/wei_algorithm.py
+++ b/apps/wei/management/commands/wei_algorithm.py
@@ -5,7 +5,7 @@ from argparse import ArgumentParser, FileType
 from django.core.management import BaseCommand
 from django.db import transaction
 
-from wei.forms import CurrentSurvey
+from ...forms import CurrentSurvey
 
 
 class Command(BaseCommand):
diff --git a/apps/wei/tests/test_wei_algorithm_2021.py b/apps/wei/tests/test_wei_algorithm_2021.py
new file mode 100644
index 0000000000000000000000000000000000000000..e1aab59b71e324b39cde1752f8e3c11884d2537a
--- /dev/null
+++ b/apps/wei/tests/test_wei_algorithm_2021.py
@@ -0,0 +1,109 @@
+# Copyright (C) 2018-2021 by BDE ENS Paris-Saclay
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+import random
+
+from django.contrib.auth.models import User
+from django.test import TestCase
+
+from ..forms.surveys.wei2021 import WEIBusInformation2021, WEISurvey2021, WORDS, WEISurveyInformation2021
+from ..models import Bus, WEIClub, WEIRegistration
+
+
+class TestWEIAlgorithm(TestCase):
+    """
+    Run some tests to ensure that the WEI algorithm is working well.
+    """
+    fixtures = ('initial',)
+
+    def setUp(self):
+        """
+        Create some test data, with one WEI and 10 buses with random score attributions.
+        """
+        self.wei = WEIClub.objects.create(
+            name="WEI 2021",
+            email="wei2021@example.com",
+            date_start='2021-09-17',
+            date_end='2021-09-19',
+        )
+
+        self.buses = []
+        for i in range(10):
+            bus = Bus.objects.create(wei=self.wei, name=f"Bus {i}", size=10)
+            self.buses.append(bus)
+            information = WEIBusInformation2021(bus)
+            for word in WORDS:
+                information.scores[word] = random.randint(0, 101)
+            information.save()
+            bus.save()
+
+    def test_survey_algorithm_small(self):
+        """
+        There are only a few people in each bus, ensure that each person has its best bus
+        """
+        # Add a few users
+        for i in range(10):
+            user = User.objects.create(username=f"user{i}")
+            registration = WEIRegistration.objects.create(
+                user=user,
+                wei=self.wei,
+                first_year=True,
+                birth_date='2000-01-01',
+            )
+            information = WEISurveyInformation2021(registration)
+            for j in range(1, 21):
+                setattr(information, f'word{j}', random.choice(WORDS))
+            information.step = 20
+            information.save(registration)
+            registration.save()
+
+        # Run algorithm
+        WEISurvey2021.get_algorithm_class()().run_algorithm()
+
+        # Ensure that everyone has its first choice
+        for r in WEIRegistration.objects.filter(wei=self.wei).all():
+            survey = WEISurvey2021(r)
+            preferred_bus = survey.ordered_buses()[0][0]
+            chosen_bus = survey.information.get_selected_bus()
+            self.assertEqual(preferred_bus, chosen_bus)
+
+    def test_survey_algorithm_full(self):
+        """
+        Buses are full of first year people, ensure that they are happy
+        """
+        # Add a lot of users
+        for i in range(95):
+            user = User.objects.create(username=f"user{i}")
+            registration = WEIRegistration.objects.create(
+                user=user,
+                wei=self.wei,
+                first_year=True,
+                birth_date='2000-01-01',
+            )
+            information = WEISurveyInformation2021(registration)
+            for j in range(1, 21):
+                setattr(information, f'word{j}', random.choice(WORDS))
+            information.step = 20
+            information.save(registration)
+            registration.save()
+
+        # Run algorithm
+        WEISurvey2021.get_algorithm_class()().run_algorithm()
+
+        penalty = 0
+        # Ensure that everyone seems to be happy
+        # We attribute a penalty for each user that didn't have its first choice
+        # The penalty is the square of the distance between the score of the preferred bus
+        # and the score of the attributed bus
+        # We consider it acceptable if the mean of this distance is lower than 5 %
+        for r in WEIRegistration.objects.filter(wei=self.wei).all():
+            survey = WEISurvey2021(r)
+            chosen_bus = survey.information.get_selected_bus()
+            buses = survey.ordered_buses()
+            score = min(v for bus, v in buses if bus == chosen_bus)
+            max_score = buses[0][1]
+            penalty += (max_score - score) ** 2
+
+            self.assertLessEqual(max_score - score, 25)  # Always less than 25 % of tolerance
+
+        self.assertLessEqual(penalty / 100, 25)  # Tolerance of 5 %
diff --git a/apps/wei/tests/test_wei_registration.py b/apps/wei/tests/test_wei_registration.py
index 71eded3aed0adbc1fbddd46c29dc7240e77f014e..2a49a5d88c32f0bf0d160aa60e0330b310868843 100644
--- a/apps/wei/tests/test_wei_registration.py
+++ b/apps/wei/tests/test_wei_registration.py
@@ -3,7 +3,6 @@
 
 import subprocess
 from datetime import timedelta, date
-from unittest import skip
 
 from api.tests import TestAPI
 from django.conf import settings
@@ -813,10 +812,6 @@ class TestWEISurveyAlgorithm(TestCase):
         )
         CurrentSurvey(self.registration).save()
 
-    @skip  # FIXME Write good unit tests
-    def test_survey_algorithm(self):
-        CurrentSurvey.get_algorithm_class()().run_algorithm()
-
 
 class TestWeiAPI(TestAPI):
     def setUp(self) -> None: