diff --git a/Gemfile b/Gemfile
index 3199e0a8f6cb36ac53ae858dbb4fbfffa113a430..7a17dcdf35969ce8e27ddfcaf125023e91f53e71 100644
--- a/Gemfile
+++ b/Gemfile
@@ -66,7 +66,7 @@ group :test do
   gem 'minitest-stub-const' # why?
 
   # generating test data
-  gem 'factory_girl_rails'  # test data factories
+  gem 'factory_bot_rails'   # test data factories
   gem 'faker'               # names and numbers for test data
   gem 'psych', '~> 2.2.4'   # needed by faker
 
diff --git a/Gemfile.lock b/Gemfile.lock
index 430155be987af929db125ac8724d342ea901de41..3cae8eb518502be7f1b3d6ee83753966e6cf2cd9 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -129,10 +129,10 @@ GEM
     equalizer (0.0.11)
     erubis (2.7.0)
     execjs (2.7.0)
-    factory_girl (4.9.0)
+    factory_bot (4.8.2)
       activesupport (>= 3.0.0)
-    factory_girl_rails (4.9.0)
-      factory_girl (~> 4.9.0)
+    factory_bot_rails (4.8.2)
+      factory_bot (~> 4.8.2)
       railties (>= 3.0.0)
     fake_braintree (0.8.0)
       activesupport
@@ -359,7 +359,7 @@ DEPENDENCIES
   couchrest_session_store (~> 0.4.2)
   cucumber (~> 2.4.0)
   cucumber-rails
-  factory_girl_rails
+  factory_bot_rails
   fake_braintree
   faker
   haml-rails
diff --git a/engines/billing/test/broken/admin_customer_test.rb b/engines/billing/test/broken/admin_customer_test.rb
index df92a0d708739e3b4488f7cfd7338c315e87ab9d..2fb80ca17ad9ca8e82a8ea4f9f4b7c4f2e1afe73 100644
--- a/engines/billing/test/broken/admin_customer_test.rb
+++ b/engines/billing/test/broken/admin_customer_test.rb
@@ -4,8 +4,8 @@ require 'fake_braintree'
 class AdminCustomerTest < BraintreeIntegrationTest
 
   setup do
-    @admin = User.find_by_login('admin') || FactoryGirl.create(:user, login: 'admin')
-    @user = FactoryGirl.create(:user)
+    @admin = User.find_by_login('admin') || FactoryBot.create(:user, login: 'admin')
+    @user = FactoryBot.create(:user)
   end
 
   teardown do
diff --git a/engines/billing/test/broken/customer_creation_test.rb b/engines/billing/test/broken/customer_creation_test.rb
index 90319a9689bb07d6a43343bea769e4087a633b1b..da171c43c3504d31158f9aac042df71967f260cc 100644
--- a/engines/billing/test/broken/customer_creation_test.rb
+++ b/engines/billing/test/broken/customer_creation_test.rb
@@ -4,7 +4,7 @@ require 'fake_braintree'
 class CustomerCreationTest < BraintreeIntegrationTest
 
   setup do
-    @user = FactoryGirl.create(:user)
+    @user = FactoryBot.create(:user)
     login_as @user
   end
 
@@ -38,7 +38,7 @@ class CustomerCreationTest < BraintreeIntegrationTest
   # for a broken customer
   test "successfully confirms customer creation" do
     response = post_transparent_redirect :create_customer_data,
-      customer: FactoryGirl.attributes_for(:braintree_customer),
+      customer: FactoryBot.attributes_for(:braintree_customer),
       redirect_url: confirm_customer_url
 
     assert_difference("Customer.count") do
@@ -57,7 +57,7 @@ class CustomerCreationTest < BraintreeIntegrationTest
     FakeBraintree.decline_all_cards!
 
     response = post_transparent_redirect :create_customer_data,
-      customer: FactoryGirl.attributes_for(:broken_customer),
+      customer: FactoryBot.attributes_for(:broken_customer),
       redirect_url: confirm_customer_url
 
     assert FakeBraintree.decline_all_cards?
diff --git a/engines/billing/test/broken/subscription_test.rb b/engines/billing/test/broken/subscription_test.rb
index cd010bde849ebf9dc95722627dec6de5bc91acb8..dd9bba90a4154d703c62e7d42429d6e7a32a6249 100644
--- a/engines/billing/test/broken/subscription_test.rb
+++ b/engines/billing/test/broken/subscription_test.rb
@@ -6,7 +6,7 @@ class SubscriptionTest < BraintreeIntegrationTest
   include StubRecordHelper
 
   setup do
-    @admin = User.find_by_login('admin') || FactoryGirl.create(:user, login: 'admin')
+    @admin = User.find_by_login('admin') || FactoryBot.create(:user, login: 'admin')
     @customer = stub_customer
     @braintree_customer = @customer.braintree_customer
     response = Braintree::Subscription.create plan_id: '5',
diff --git a/engines/billing/test/factories.rb b/engines/billing/test/factories.rb
index 6352211aeb902256ac66ccc661095ad7a925c093..572da48ff730d89fc2487441579d5b6ae175be57 100644
--- a/engines/billing/test/factories.rb
+++ b/engines/billing/test/factories.rb
@@ -1,4 +1,4 @@
-FactoryGirl.define do
+FactoryBot.define do
 
   TEST_CC_NUMBER = %w(4111 1111 1111 1111).join
 
diff --git a/engines/support/test/factories.rb b/engines/support/test/factories.rb
index 3fc28b35f59ac1cf519dce9a9d4620bea66d9645..7bc2ec765b595be18fa786078168a439ab651993 100644
--- a/engines/support/test/factories.rb
+++ b/engines/support/test/factories.rb
@@ -1,4 +1,4 @@
-FactoryGirl.define do
+FactoryBot.define do
 
   factory :ticket do
     subject { Faker::Lorem.sentence }
@@ -14,7 +14,7 @@ FactoryGirl.define do
     end
 
     factory :ticket_with_creator do
-      created_by { FactoryGirl.create(:user).id }
+      created_by { FactoryBot.create(:user).id }
     end
 
   end
diff --git a/engines/support/test/functional/ticket_comments_test.rb b/engines/support/test/functional/ticket_comments_test.rb
index c6c143a019c64b2f8570173ceced82a646b20988..826850d52d8c54b86914018150d61228f3e3ebe2 100644
--- a/engines/support/test/functional/ticket_comments_test.rb
+++ b/engines/support/test/functional/ticket_comments_test.rb
@@ -9,7 +9,7 @@ class TicketsCommentsTest < ActionController::TestCase
   end
 
   test "add comment to unauthenticated ticket" do
-    ticket = FactoryGirl.create :ticket, :created_by => nil
+    ticket = create_ticket :created_by => nil
 
     assert_difference('Ticket.find(ticket.id).comments.count') do
       put :update, :id => ticket.id,
@@ -25,7 +25,7 @@ class TicketsCommentsTest < ActionController::TestCase
   test "add comment to own authenticated ticket" do
 
     login
-    ticket = FactoryGirl.create :ticket, :created_by => @current_user.id
+    ticket = create_ticket :created_by => @current_user.id
 
     #they should be able to comment if it is their ticket:
     assert_difference('Ticket.find(ticket.id).comments.count') do
@@ -42,7 +42,7 @@ class TicketsCommentsTest < ActionController::TestCase
   test "cannot comment if it is another users ticket" do
     other_user = find_record :user
     login :is_admin? => false, :email => nil
-    ticket = FactoryGirl.create :ticket, :created_by => other_user.id
+    ticket = create_ticket :created_by => other_user.id
     # they should *not* be able to comment if it is not their ticket
     put :update, :id => ticket.id, :ticket => {:comments_attributes => {"0" => {"body" =>"not allowed comment"}} }
     assert_response :redirect
@@ -53,8 +53,8 @@ class TicketsCommentsTest < ActionController::TestCase
 
   test "authenticated comment on an anonymous ticket adds to my tickets" do
     login
-    ticket = FactoryGirl.create :ticket
-    other_ticket = FactoryGirl.create :ticket
+    ticket = create_ticket
+    other_ticket = create_ticket
     put :update, :id => ticket.id,
       :ticket => {:comments_attributes => {"0" => {"body" =>"NEWER comment"}} }
     assert_not_nil assigns(:ticket).comments.last.posted_by
@@ -71,7 +71,7 @@ class TicketsCommentsTest < ActionController::TestCase
     admin = find_record :user, @current_user
     other_user = find_record :user
 
-    ticket = FactoryGirl.create :ticket, :created_by => other_user.id
+    ticket = create_ticket :created_by => other_user.id
 
     #admin should be able to comment:
     assert_difference('Ticket.find(ticket.id).comments.count') do
@@ -84,7 +84,7 @@ class TicketsCommentsTest < ActionController::TestCase
   end
 
   test "commenting on a ticket adds to tickets that are mine" do
-    testticket = FactoryGirl.create :ticket
+    testticket = create_ticket
     user = find_record :admin_user
     login user
     get :index, {:user_id => user.id, :open_status => "open"}
@@ -98,4 +98,8 @@ class TicketsCommentsTest < ActionController::TestCase
     assert_equal assigns(:ticket).comments.last.posted_by, @current_user.id
   end
 
+  def create_ticket(attrs = {})
+    FactoryBot.create :ticket, attrs
+  end
+
 end
diff --git a/engines/support/test/functional/tickets_controller_test.rb b/engines/support/test/functional/tickets_controller_test.rb
index 2f1e661d6cee9fee32fb21dafd71386666ab563e..e86ec11c882c99e8a016b210cb8c3983ad6a2d93 100644
--- a/engines/support/test/functional/tickets_controller_test.rb
+++ b/engines/support/test/functional/tickets_controller_test.rb
@@ -137,7 +137,7 @@ class TicketsControllerTest < ActionController::TestCase
 
   test "close ticket" do
     login
-    open_ticket = FactoryGirl.create :ticket_with_comment,
+    open_ticket = FactoryBot.create :ticket_with_comment,
       created_by: @current_user.id
     post :close, id: open_ticket.id
     assert !open_ticket.reload.is_open
@@ -145,7 +145,7 @@ class TicketsControllerTest < ActionController::TestCase
 
   test "reopen ticket" do
     login
-    open_ticket = FactoryGirl.create :ticket_with_comment,
+    open_ticket = FactoryBot.create :ticket_with_comment,
       created_by: @current_user.id, is_open: false
     post :open, id: open_ticket.id
     assert open_ticket.reload.is_open
diff --git a/engines/support/test/functional/tickets_list_test.rb b/engines/support/test/functional/tickets_list_test.rb
index ab76f5fad4775dc1d13b145ec62a5de2b649bbc6..0e676b835fcae4feac2541d829141c8212880972 100644
--- a/engines/support/test/functional/tickets_list_test.rb
+++ b/engines/support/test/functional/tickets_list_test.rb
@@ -12,7 +12,7 @@ class TicketsListTest < ActionController::TestCase
 
   test "tickets by admin" do
       other_user = find_record :user
-      ticket = FactoryGirl.create :ticket, :created_by => other_user.id
+      ticket = create_ticket :created_by => other_user.id
 
       login :is_admin? => true
 
@@ -29,7 +29,7 @@ class TicketsListTest < ActionController::TestCase
 
 
   test "admin_status mine vs all" do
-    testticket = FactoryGirl.create :ticket
+    testticket = create_ticket
     user = find_record :user
     login :is_admin? => true, :email => nil
 
@@ -40,8 +40,7 @@ class TicketsListTest < ActionController::TestCase
   end
 
   test "admin ticket ordering" do
-    tickets = FactoryGirl.create_list :ticket, 2
-
+    2.times { create_ticket }
     login :is_admin? => true, :email => nil
     get :index, {:admin_status => "all", :open_status => "open", :sort_order => 'created_at_desc'}
 
@@ -63,9 +62,9 @@ class TicketsListTest < ActionController::TestCase
 
   test "own tickets include tickets commented upon" do
     login
-    ticket = FactoryGirl.create :ticket
-    other_ticket = FactoryGirl.create :ticket
-    comment = FactoryGirl.build(:ticket_comment, posted_by: @current_user.id)
+    ticket = create_ticket
+    other_ticket = create_ticket
+    comment = FactoryBot.build :ticket_comment, posted_by: @current_user.id
     ticket.comments << comment
     ticket.save
 
@@ -77,20 +76,16 @@ class TicketsListTest < ActionController::TestCase
 
   test "list all tickets created by user" do
     login
-    ticket = FactoryGirl.create :ticket_with_comment,
-      created_by: @current_user.id
-    other_ticket = FactoryGirl.create :ticket_with_comment,
-      created_by: @current_user.id
+    ticket = create_ticket_with_comment created_by: @current_user.id
+    other_ticket = create_ticket_with_comment created_by: @current_user.id
     get :index, {:open_status => "open"}
     assert_equal 2, assigns[:all_tickets].count
   end
 
   test "closing ticket removes from open tickets list" do
     login
-    ticket = FactoryGirl.create :ticket_with_comment,
-      created_by: @current_user.id
-    other_ticket = FactoryGirl.create :ticket_with_comment,
-      created_by: @current_user.id
+    ticket = create_ticket_with_comment created_by: @current_user.id
+    other_ticket = create_ticket_with_comment created_by: @current_user.id
     other_ticket.reload
     other_ticket.close
     other_ticket.save
@@ -100,23 +95,29 @@ class TicketsListTest < ActionController::TestCase
 
   test "list closed tickets only" do
     login
-    open_ticket = FactoryGirl.create :ticket_with_comment,
-      created_by: @current_user.id
-    closed_ticket = FactoryGirl.create :ticket_with_comment,
-      created_by: @current_user.id, is_open: false
+    open_ticket = create_ticket_with_comment created_by: @current_user.id
+    closed_ticket = create_ticket_with_comment created_by: @current_user.id,
+      is_open: false
     get :index, {:open_status => "closed"}
     assert_equal [closed_ticket], assigns(:all_tickets).all
   end
 
   test "list all tickets" do
     login
-    open_ticket = FactoryGirl.create :ticket_with_comment,
-      created_by: @current_user.id
-    closed_ticket = FactoryGirl.create :ticket_with_comment,
-      created_by: @current_user.id, is_open: false
+    open_ticket = create_ticket_with_comment created_by: @current_user.id
+    closed_ticket = create_ticket_with_comment created_by: @current_user.id,
+      is_open: false
     get :index, {:open_status => "all"}
     assert_equal 2, assigns(:all_tickets).count
     assert assigns(:all_tickets).include?(open_ticket)
     assert assigns(:all_tickets).include?(closed_ticket)
   end
+
+  def create_ticket(attrs = {})
+    FactoryBot.create :ticket, attrs
+  end
+
+  def create_ticket_with_comment(attrs = {})
+    FactoryBot.create :ticket_with_comment, attrs
+  end
 end
diff --git a/engines/support/test/integration/create_ticket_test.rb b/engines/support/test/integration/create_ticket_test.rb
index fcdc6b8fde593e211ba1a237515ccaa3dcedcca9..cccd2b29ab08ddd3f6b8cdfd9127ede2fa53e70d 100644
--- a/engines/support/test/integration/create_ticket_test.rb
+++ b/engines/support/test/integration/create_ticket_test.rb
@@ -34,7 +34,9 @@ class CreateTicketTest < BrowserIntegrationTest
   end
 
   test "prefills fields" do
-    login FactoryGirl.create(:premium_user, :invite_code => @testcode.invite_code)
+    user = FactoryBot.create :premium_user,
+      :invite_code => @testcode.invite_code
+    login user
     visit '/'
     click_on "Support Tickets"
     click_on "New Ticket"
@@ -53,7 +55,9 @@ class CreateTicketTest < BrowserIntegrationTest
   end
 
   test "cleared email field should remain clear" do
-    login FactoryGirl.create(:premium_user, :invite_code => @testcode.invite_code)
+    user = FactoryBot.create :premium_user,
+      :invite_code => @testcode.invite_code
+    login user
     visit '/'
     click_on "Support Tickets"
     click_on "New Ticket"
diff --git a/engines/support/test/unit/account_extension_test.rb b/engines/support/test/unit/account_extension_test.rb
index 1b97062d1f92dfb9fe78a84943ebdb1691469dc3..88dc6814fed85bae70f6fe9173ad8edf29609f6f 100644
--- a/engines/support/test/unit/account_extension_test.rb
+++ b/engines/support/test/unit/account_extension_test.rb
@@ -7,7 +7,7 @@ class AccountExtensionTest < ActiveSupport::TestCase
   end
 
   test "destroying an account triggers ticket destruction" do
-    t = FactoryGirl.create :ticket_with_creator
+    t = FactoryBot.create :ticket_with_creator
     u = t.created_by_user
     Account.new(u).destroy
     assert_nil Ticket.find(t.id)
diff --git a/engines/support/test/unit/ticket_test.rb b/engines/support/test/unit/ticket_test.rb
index 048704c8692d646cbeabb2b3f95d8c33af66ebb8..78c81bd7c8474d46bb6ccc16b4c3b12d7b9a5254 100644
--- a/engines/support/test/unit/ticket_test.rb
+++ b/engines/support/test/unit/ticket_test.rb
@@ -7,22 +7,22 @@ class TicketTest < ActiveSupport::TestCase
   end
 
   test "ticket with default attribs is valid" do
-    t = FactoryGirl.build :ticket
+    t = build_ticket
     assert t.valid?, t.errors.full_messages.to_sentence
   end
 
   test "ticket without email is valid" do
-    t = FactoryGirl.build :ticket, email: ""
+    t = build_ticket email: ""
     assert t.valid?, t.errors.full_messages.to_sentence
   end
 
   test "ticket validates email format" do
-    t = FactoryGirl.build :ticket, email: "invalid email"
+    t = build_ticket email: "invalid email"
     assert !t.valid?
   end
 
   test "ticket open states" do
-    t = FactoryGirl.build :ticket
+    t = build_ticket
     assert t.is_open
     t.close
     assert !t.is_open
@@ -31,7 +31,7 @@ class TicketTest < ActiveSupport::TestCase
   end
 
   test "creation validated" do
-    user = FactoryGirl.create :user
+    user = create_user
     @sample = Ticket.new
     assert !@sample.is_creator_validated?
     @sample.created_by = user.id
@@ -39,7 +39,7 @@ class TicketTest < ActiveSupport::TestCase
   end
 
   test "destroy all tickets from a user" do
-    t = FactoryGirl.create :ticket_with_creator
+    t = FactoryBot.create :ticket_with_creator
     u = t.created_by_user
     Ticket.destroy_all_from(u)
     assert_nil Ticket.find(t.id)
@@ -89,4 +89,13 @@ class TicketTest < ActiveSupport::TestCase
     assert_equal [], Ticket.by_includes_post_by.key('123').all;
   end
 
+  protected
+
+  def build_ticket(attrs = {})
+    FactoryBot.build :ticket, attrs
+  end
+
+  def create_user
+    FactoryBot.create :user
+  end
 end
diff --git a/features/step_definitions/auth_steps.rb b/features/step_definitions/auth_steps.rb
index 52c92ee32696ecc43735e0cea1950e921f105e12..81c5fc549341bc76bda7e54140e4a7cd4cb82f40 100644
--- a/features/step_definitions/auth_steps.rb
+++ b/features/step_definitions/auth_steps.rb
@@ -1,7 +1,7 @@
 Given /^I authenticated$/ do
   @testcode = InviteCode.new
   @testcode.save!
-  @user = FactoryGirl.create(:user, :invite_code => @testcode.invite_code)
+  @user = FactoryBot.create(:user, :invite_code => @testcode.invite_code)
   @my_auth_token = Token.create user_id: @user.id
 end
 
diff --git a/features/step_definitions/messages_steps.rb b/features/step_definitions/messages_steps.rb
index 30bc7c3cfcf211ba24645ef86abdaf6cf0f6db51..89d0196dcc4d8f6ef69143baf530bca272cc3181 100644
--- a/features/step_definitions/messages_steps.rb
+++ b/features/step_definitions/messages_steps.rb
@@ -1,5 +1,5 @@
 Given /^there is a message for me$/ do
-  @message = FactoryGirl.create :message, user_ids_to_show: [@user.id]
+  @message = FactoryBot.create :message, user_ids_to_show: [@user.id]
 end
 
 Given /^there is a message for me with:$/ do |options|
@@ -8,7 +8,7 @@ Given /^there is a message for me with:$/ do |options|
   if old_message = Message.find(attributes['id'])
     old_message.destroy
   end
-  @message = FactoryGirl.create :message, attributes
+  @message = FactoryBot.create :message, attributes
 end
 
 Given(/^that message is marked as read$/) do
diff --git a/test/factories.rb b/test/factories.rb
index 5d49729167d2c97ec219862c9982f91d34d144b5..f2878425e1017bb5a881cd80c237959b0a53f9c5 100644
--- a/test/factories.rb
+++ b/test/factories.rb
@@ -3,7 +3,7 @@ Dir.glob(ENGINE_FACTORY_FILES) do |factory_file|
   require factory_file
 end
 
-FactoryGirl.define do
+FactoryBot.define do
 
   factory :user do
     # Faker::Internet.user_name alone was sometimes
diff --git a/test/functional/api/identities_controller_test.rb b/test/functional/api/identities_controller_test.rb
index 57345c8f48b96a9b017d95ef52a0b7f54268b80f..bb5608e61aef03c3576d3291a973b5dc2c4c28a5 100644
--- a/test/functional/api/identities_controller_test.rb
+++ b/test/functional/api/identities_controller_test.rb
@@ -4,7 +4,7 @@ class Api::IdentitiesControllerTest < ApiControllerTest
 
   test "api monitor can fetch identity" do
     monitor_auth do
-      identity = FactoryGirl.create :identity
+      identity = create_identity
       api_get :show, :id => identity.address, :format => 'json'
       assert_response :success
       assert_equal identity, assigns(:identity)
@@ -16,9 +16,12 @@ class Api::IdentitiesControllerTest < ApiControllerTest
 
 
   test "anonymous cannot fetch identity" do
-    identity = FactoryGirl.create :identity
+    identity = create_identity
     api_get :show, :id => identity.address, :format => 'json'
     assert_response :forbidden
   end
 
+  def create_identity
+    FactoryBot.create :identity
+  end
 end
diff --git a/test/functional/api/messages_controller_test.rb b/test/functional/api/messages_controller_test.rb
index e586980a159dc78f7f7a18f1856a1d9b310db12b..31ba2b096c5030343fa0e6f0f1e64eea30be8542 100644
--- a/test/functional/api/messages_controller_test.rb
+++ b/test/functional/api/messages_controller_test.rb
@@ -2,17 +2,12 @@ require 'test_helper'
 
 class Api::MessagesControllerTest < ApiControllerTest
 
-  setup do
-    @user = FactoryGirl.build(:user)
-    @user.save
-  end
-
   # NOTE: the available languages for test are :en and :de
   # so :es will result in english response.
 
   test "get the motd" do
     with_config("customization_directory" => Rails.root+'test/files') do
-      login @user
+      login
       api_get :index, :locale => 'es'
       body = JSON.parse(response.body)
       message1 = "<p>\"This\" is a <strong>very</strong> fine message. <a href=\"https://bitmask.net\">https://bitmask.net</a></p>\n"
@@ -23,7 +18,7 @@ class Api::MessagesControllerTest < ApiControllerTest
 
   test "get localized motd" do
     with_config("customization_directory" => Rails.root+'test/files') do
-      login @user
+      login
       api_get :index, :locale => 'de'
       body = JSON.parse(response.body)
       message1 = "<p>Dies ist eine sehr feine Nachricht. <a href=\"https://bitmask.net\">https://bitmask.net</a></p>\n"
@@ -32,7 +27,7 @@ class Api::MessagesControllerTest < ApiControllerTest
   end
 
   test "get empty motd" do
-    login @user
+    login
     api_get :index
     assert_equal "[]", response.body, "motd response should be empty if no motd directory exists"
   end
@@ -44,7 +39,7 @@ class Api::MessagesControllerTest < ApiControllerTest
 =begin
   setup do
     InviteCodeValidator.any_instance.stubs(:validate)
-    @user = FactoryGirl.build(:user)
+    @user = FactoryBot.build(:user)
     @user.save
     @message = Message.new(:text => 'a test message')
     @message.user_ids_to_show << @user.id
diff --git a/test/functional/api/users_controller_test.rb b/test/functional/api/users_controller_test.rb
index ee183f9edce4fec600ea64447fcbf7108596b0f9..dfaf95925d5061ae148b506b43c67074b9676616 100644
--- a/test/functional/api/users_controller_test.rb
+++ b/test/functional/api/users_controller_test.rb
@@ -96,7 +96,7 @@ class Api::UsersControllerTest < ApiControllerTest
   end
 
   test "admin can show user" do
-    user = FactoryGirl.create :user
+    user = FactoryBot.create :user
     login :is_admin? => true
     api_get :show, :id => 0, :login => user.login, :format => :json
     assert_response :success
@@ -109,7 +109,7 @@ class Api::UsersControllerTest < ApiControllerTest
   end
 
   test "admin can show is_admin property" do
-    admin = FactoryGirl.create :user
+    admin = FactoryBot.create :user
     with_config(admins: [admin.login]) do
       login admin
       api_get :show, :id => admin.id, :format => :json
diff --git a/test/functional/identities_controller_test.rb b/test/functional/identities_controller_test.rb
index 5af2e88b50e425da4e0ad898a3c15702c2796f27..5e46f9c2b7cf8b3532c1b48cafe37020cfb239b3 100644
--- a/test/functional/identities_controller_test.rb
+++ b/test/functional/identities_controller_test.rb
@@ -1,4 +1,4 @@
-require_relative '../test_helper'
+require 'test_helper'
 
 class IdentitiesControllerTest < ActionController::TestCase
 
@@ -26,7 +26,7 @@ class IdentitiesControllerTest < ActionController::TestCase
 
   test "admin can unblock username" do
     # an identity without user_id and destination is a blocked handle
-    identity = FactoryGirl.create :identity
+    identity = create_identity
     login :is_admin? => true
     delete :destroy, id: identity.id
     assert_response :redirect
@@ -34,13 +34,19 @@ class IdentitiesControllerTest < ActionController::TestCase
   end
 
   test "admin cannot remove main identity" do
-    user = FactoryGirl.create :user
-    identity = FactoryGirl.create :identity,
-      Identity.attributes_from_user(user)
+    user = create_user
+    identity = create_identity Identity.attributes_from_user(user)
     login :is_admin? => true
     delete :destroy, id: identity.id
     assert_response :redirect
     assert_equal identity, Identity.find(identity.id)
   end
 
+  def create_identity(attrs={})
+    FactoryBot.create :identity, attrs
+  end
+
+  def create_user
+    FactoryBot.create :user
+  end
 end
diff --git a/test/integration/api/pgp_key_test.rb b/test/integration/api/pgp_key_test.rb
index f2744e118448357702e061bee3074b18240fd580..1ffbe548adf10cfe1556a02735eda23b96449988 100644
--- a/test/integration/api/pgp_key_test.rb
+++ b/test/integration/api/pgp_key_test.rb
@@ -30,7 +30,7 @@ class PgpKeyTest < SrpTest
   protected
 
   def key
-    @key ||= FactoryGirl.build :pgp_key
+    @key ||= FactoryBot.build :pgp_key
   end
 
   def assert_invalid_key_response
diff --git a/test/integration/browser/account_livecycle_test.rb b/test/integration/browser/account_livecycle_test.rb
index 68775d301ef6528af96d630f5975b623be8a01d5..48be234d1f3716072f53f7b15205056b33909c9f 100644
--- a/test/integration/browser/account_livecycle_test.rb
+++ b/test/integration/browser/account_livecycle_test.rb
@@ -103,7 +103,7 @@ class AccountLivecycleTest < BrowserIntegrationTest
 
   test "change pgp key" do
     with_config user_actions: ['change_pgp_key'] do
-      pgp_key = FactoryGirl.build :pgp_key
+      pgp_key = FactoryBot.build :pgp_key
       username, _password = submit_signup
       click_on "Account Settings"
       within('#update_pgp_key') do
diff --git a/test/integration/browser/admin_test.rb b/test/integration/browser/admin_test.rb
index 0b43c29f3fa648e815b324d214b3420507c94103..ff36416d674f6611decd7a48f51b9495f999a074 100644
--- a/test/integration/browser/admin_test.rb
+++ b/test/integration/browser/admin_test.rb
@@ -21,7 +21,7 @@ class AdminTest < BrowserIntegrationTest
   end
 
   test "clear blocked handle" do
-    id = FactoryGirl.create :identity
+    id = FactoryBot.create :identity
     submit_signup(id.login)
     assert page.has_content?('has already been taken')
     login
diff --git a/test/integration/browser/security_test.rb b/test/integration/browser/security_test.rb
index 825d50b6bcc2ca6ead8c712fab8c3a92f50c53df..7073b762ac595a34cddacde5d8af22947411cf98 100644
--- a/test/integration/browser/security_test.rb
+++ b/test/integration/browser/security_test.rb
@@ -10,7 +10,7 @@ class SecurityTest < BrowserIntegrationTest
   test "detects attempt to circumvent SRP" do
     InviteCodeValidator.any_instance.stubs(:validate)
 
-    user = FactoryGirl.create :user
+    user = FactoryBot.create :user
     visit '/login'
     fill_in 'Username', with: user.login
     fill_in 'Password', with: "password"
diff --git a/test/support/api_integration_test.rb b/test/support/api_integration_test.rb
index 7942558584ecc7ed391cd8fc26ca2ba73a938edf..94c88e14ec2024b3d2c33e1f1cd6735cd281ebcf 100644
--- a/test/support/api_integration_test.rb
+++ b/test/support/api_integration_test.rb
@@ -22,7 +22,7 @@ class ApiIntegrationTest < ActionDispatch::IntegrationTest
     @testcode = InviteCode.new
     @testcode.save!
     options.reverse_merge! invite_code: @testcode.invite_code
-    FactoryGirl.create :user, options
+    FactoryBot.create :user, options
   end
 
   teardown do
diff --git a/test/support/browser_integration_test.rb b/test/support/browser_integration_test.rb
index d00e606653f186a8322b6e453e90700314c0efb1..cff732beb01e0aa456ea2490a76f9cd24e82c718 100644
--- a/test/support/browser_integration_test.rb
+++ b/test/support/browser_integration_test.rb
@@ -49,7 +49,7 @@ class BrowserIntegrationTest < RackStackTest
   # ApiIntegrationTest has a working implementation for RackTest
   def login(user = nil)
     InviteCodeValidator.any_instance.stubs(:validate)
-    @user ||= user ||= FactoryGirl.create(:user)
+    @user ||= user ||= FactoryBot.create(:user)
     token = Token.create user_id: user.id
     page.driver.add_header "Authorization", %Q(Token token="#{token}")
     visit '/'
diff --git a/test/support/stub_record_helper.rb b/test/support/stub_record_helper.rb
index 25138a0fd3541befb847baa694bd2bedbfef2710..4d74f2a86cc45adb7ad062f3e81d4e84be3752ea 100644
--- a/test/support/stub_record_helper.rb
+++ b/test/support/stub_record_helper.rb
@@ -26,7 +26,7 @@ module StubRecordHelper
     if record_or_method_hash && !record_or_method_hash.is_a?(Hash)
       return record_or_method_hash
     end
-    FactoryGirl.build_stubbed(factory).tap do |record|
+    FactoryBot.build_stubbed(factory).tap do |record|
       if persisted or record.persisted?
         record_or_method_hash.reverse_merge! :created_at => Time.now,
           :updated_at => Time.now, :id => Random.rand(100000).to_s
@@ -38,7 +38,7 @@ module StubRecordHelper
   # returns deep stringified attributes so they can be compared to
   # what the controller receives as params
   def record_attributes_for(factory, attribs_hash = nil)
-    FactoryGirl.attributes_for(factory, attribs_hash).tap do |attribs|
+    FactoryBot.attributes_for(factory, attribs_hash).tap do |attribs|
       attribs.keys.each do |key|
         val = attribs.delete(key)
         attribs[key.to_s] = val.is_a?(Hash) ? val.stringify_keys! : val
diff --git a/test/unit/account_test.rb b/test/unit/account_test.rb
index ebfff6b993ef3afc370007d19d7d08af5a2e9b1c..8923a81ba361fb56e12543a82af913b902dcb0cd 100644
--- a/test/unit/account_test.rb
+++ b/test/unit/account_test.rb
@@ -58,7 +58,7 @@ class AccountTest < ActiveSupport::TestCase
 
   test "error on invalid username" do
     with_config invite_required: false do
-      attributes = FactoryGirl.attributes_for :user, login: "a"
+      attributes = user_attributes login: "a"
       @user = Account.create attributes
       assert !@user.valid?
       assert_has_errors @user, login: "Must have at least two characters"
@@ -155,7 +155,8 @@ class AccountTest < ActiveSupport::TestCase
   end
 
   test "Invite code stays zero when invite code is not used" do
-    invalid_user = FactoryGirl.build(:user, :invite_code => @testcode.invite_code)
+    invalid_user = FactoryBot.build :user,
+      :invite_code => @testcode.invite_code
     invalid_user.save
     user_code = InviteCode.find_by_invite_code invalid_user.invite_code
     user_code.save
@@ -206,7 +207,7 @@ class AccountTest < ActiveSupport::TestCase
   end
 
   def user_attributes(attrs = {})
-    FactoryGirl.attributes_for :user, attrs
+    FactoryBot.attributes_for :user, attrs
   end
 
 end
diff --git a/test/unit/invite_code_validator_test.rb b/test/unit/invite_code_validator_test.rb
index 934ba2e10a442fa08e2d90291ff6edfc4a6e5ef1..7c3501a8114334225298195398b31b7ccf067ce1 100644
--- a/test/unit/invite_code_validator_test.rb
+++ b/test/unit/invite_code_validator_test.rb
@@ -3,14 +3,14 @@ require 'test_helper'
 class InviteCodeValidatorTest < ActiveSupport::TestCase
   test "user should not be created with invalid invite code" do
     with_config invite_required: true do
-      invalid_user = FactoryGirl.build(:user)
+      invalid_user = build_user
 
       assert !invalid_user.valid?
     end
   end
 
   test "user should be created with valid invite code" do
-    valid_user = FactoryGirl.build(:user)
+    valid_user = build_user
     valid_code = InviteCode.create
     valid_user.invite_code = valid_code.invite_code
 
@@ -19,7 +19,7 @@ class InviteCodeValidatorTest < ActiveSupport::TestCase
 
   test "trying to create a user with invalid invite code should add error" do
     with_config invite_required: true do
-    invalid_user = FactoryGirl.build(:user, :invite_code => "a non-existent code")
+    invalid_user = build_user :invite_code => "a non-existent code"
 
     invalid_user.valid?
 
@@ -36,7 +36,7 @@ class InviteCodeValidatorTest < ActiveSupport::TestCase
     user_code.invite_count = 1
     user_code.save
 
-    user = FactoryGirl.build :user
+    user = build_user
     user.invite_code = user_code.invite_code
 
     validator.validate(user)
@@ -51,7 +51,7 @@ class InviteCodeValidatorTest < ActiveSupport::TestCase
     user_code = InviteCode.create
     user_code.save
 
-    user = FactoryGirl.build :user
+    user = build_user
     user.invite_code = user_code.invite_code
 
     validator.validate(user)
@@ -64,7 +64,7 @@ class InviteCodeValidatorTest < ActiveSupport::TestCase
 
     user_code = InviteCode.create
 
-    user = FactoryGirl.build :user
+    user = build_user
     user.invite_code = user_code.invite_code
 
     validator.validate(user)
@@ -75,7 +75,7 @@ class InviteCodeValidatorTest < ActiveSupport::TestCase
   test "There is an error message if the invite code does not exist" do
     validator = InviteCodeValidator.new
 
-    user = FactoryGirl.build :user
+    user = build_user
     user.invite_code = "wrongcode"
 
     validator.validate(user)
@@ -83,4 +83,7 @@ class InviteCodeValidatorTest < ActiveSupport::TestCase
     assert_equal ["This is not a valid code"], user.errors[:invite_code]
   end
 
+  def build_user(attrs = {})
+    FactoryBot.build :user, attrs
+  end
 end
diff --git a/test/unit/token_test.rb b/test/unit/token_test.rb
index ce7edaaf6849eea4dcf5d3968bc13c3e7d86713d..3015c9ab7ac1fa32d9299a4cb5d8a3a13829d227 100644
--- a/test/unit/token_test.rb
+++ b/test/unit/token_test.rb
@@ -64,7 +64,7 @@ class TokenTest < ActiveSupport::TestCase
   end
 
   test "Token.destroy_all_expired is noop if no expiry is set" do
-    expired = FactoryGirl.create :token, last_seen_at: 2.hours.ago
+    expired = create_token last_seen_at: 2.hours.ago
     with_config auth: {} do
       Token.destroy_all_expired
     end
@@ -72,8 +72,8 @@ class TokenTest < ActiveSupport::TestCase
   end
 
   test "Token.destroy_all_expired cleans up expired tokens only" do
-    expired = FactoryGirl.create :token, last_seen_at: 2.hours.ago
-    fresh = FactoryGirl.create :token
+    expired = create_token last_seen_at: 2.hours.ago
+    fresh = create_token
     with_config auth: {token_expires_after: 60} do
       Token.destroy_all_expired
     end
@@ -83,7 +83,7 @@ class TokenTest < ActiveSupport::TestCase
   end
 
   test "Token.destroy_all_expired does not interfere with expired.authenticate" do
-    expired = FactoryGirl.create :token, last_seen_at: 2.hours.ago
+    expired = create_token last_seen_at: 2.hours.ago
     with_config auth: {token_expires_after: 60} do
       Token.destroy_all_expired
     end
@@ -91,7 +91,7 @@ class TokenTest < ActiveSupport::TestCase
   end
 
   test "active logout (destroy) prevents reuse" do
-    token = FactoryGirl.create :token
+    token = create_token
     same = Token.find(token.id)
     token.destroy
     assert_raises CouchRest::NotFound do
@@ -100,7 +100,7 @@ class TokenTest < ActiveSupport::TestCase
   end
 
   test "logout works on prolonged token" do
-    token = FactoryGirl.create :token
+    token = create_token
     same = Token.find(token.id)
     token.touch
     same.destroy
@@ -108,11 +108,14 @@ class TokenTest < ActiveSupport::TestCase
   end
 
   test 'second destroy carries on' do
-    token = FactoryGirl.create :token
+    token = create_token
     same = Token.find(token.id)
     token.destroy
     same.destroy
     assert_nil Token.find(same.id)
   end
 
+  def create_token(attrs = {})
+    FactoryBot.create :token, attrs
+  end
 end
diff --git a/test/unit/user_test.rb b/test/unit/user_test.rb
index ab7add00b9c608bed48333fdc7977a57ba259880..bd05170e3f89443c02084a6c4a7bda5131249129 100644
--- a/test/unit/user_test.rb
+++ b/test/unit/user_test.rb
@@ -5,7 +5,7 @@ class UserTest < ActiveSupport::TestCase
   include SRP::Util
   setup do
     InviteCodeValidator.any_instance.stubs(:validate)
-    @user = FactoryGirl.build(:user)
+    @user = FactoryBot.build(:user)
   end
 
   test "don't find a user with login nil" do
@@ -62,13 +62,13 @@ class UserTest < ActiveSupport::TestCase
   end
 
   test "login needs to be unique" do
-    other_user = FactoryGirl.create :user, login: @user.login
+    other_user = FactoryBot.create :user, login: @user.login
     assert !@user.valid?
     other_user.destroy
   end
 
   test "login needs to be unique amongst aliases" do
-    other_user = FactoryGirl.create :user
+    other_user = FactoryBot.create :user
     id = Identity.create_for other_user, address: @user.login
     assert !@user.valid?
     id.destroy