diff --git a/Gemfile b/Gemfile
index 43a669b7..f81e1de1 100644
--- a/Gemfile
+++ b/Gemfile
@@ -105,4 +105,5 @@ group :development, :test do
   gem 'brakeman'
   gem 'guard-brakeman'
   gem 'timecop'
+  gem 'rails-controller-testing'
 end
diff --git a/Gemfile.lock b/Gemfile.lock
index ee793309..fd7eed2a 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -344,6 +344,10 @@ GEM
     rails-assets-growl (1.3.5)
       rails-assets-jquery
     rails-assets-jquery (2.2.4)
+    rails-controller-testing (1.0.4)
+      actionpack (>= 5.0.1.x)
+      actionview (>= 5.0.1.x)
+      activesupport (>= 5.0.1.x)
     rails-dom-testing (2.0.3)
       activesupport (>= 4.2.0)
       nokogiri (>= 1.6)
@@ -551,6 +555,7 @@ DEPENDENCIES
   rails (~> 5.2)
   rails-assets-growl!
   rails-assets-jquery (~> 2.2.0)!
+  rails-controller-testing
   rails-i18n (~> 5.0)
   rails_admin
   rake
diff --git a/spec/controllers/announcement_controller_spec.rb b/spec/controllers/announcement_controller_spec.rb
new file mode 100644
index 00000000..51649e3c
--- /dev/null
+++ b/spec/controllers/announcement_controller_spec.rb
@@ -0,0 +1,159 @@
+# frozen_string_literal: true
+
+require "rails_helper"
+
+describe AnnouncementController, type: :controller do
+  let(:user) { FactoryBot.create(:user) }
+  before(:each) { user.add_role :administrator }
+
+  describe "#index" do
+    subject { get :index }
+
+    context "user signed in" do
+      before(:each) { sign_in(user) }
+
+      it "renders the index template" do
+        subject
+        expect(response).to render_template(:index)
+      end
+
+      context "no announcements" do
+        it "@announcements is empty" do
+          subject
+          expect(assigns(:announcements)).to be_blank
+        end
+      end
+
+      context "one announcement" do
+        let!(:announcement) { Announcement.create(content: "I am announcement", user: user, starts_at: Time.current, ends_at: Time.current + 2.days) }
+
+        it "includes the announcement in the @announcements assign" do
+          subject
+          expect(assigns(:announcements)).to include(announcement)
+        end
+      end
+    end
+  end
+
+  describe "#new" do
+    subject { get :new }
+
+    context "user signed in" do
+      before(:each) { sign_in(user) }
+
+      it "renders the new template" do
+        subject
+        expect(response).to render_template(:new)
+      end
+    end
+  end
+
+  describe "#create" do
+    let :announcement_params do
+      {
+        announcement: {
+          content: "I like dogs!",
+          starts_at: Time.current,
+          ends_at: Time.current + 2.days
+        }
+      }
+    end
+
+    subject { post :create, params: announcement_params }
+
+    context "user signed in" do
+      before(:each) { sign_in(user) }
+
+      it "creates an announcement" do
+        expect { subject }.to change { Announcement.count }.by(1)
+      end
+
+      it "redirects to announcement#index" do
+        subject
+        expect(response).to redirect_to(:announcement_index)
+      end
+    end
+  end
+
+  describe "#edit" do
+    let! :announcement do
+      Announcement.create(content: "Dogs are pretty cool, I guess",
+                          starts_at: Time.current + 3.days,
+                          ends_at: Time.current + 10.days,
+                          user: user)
+    end
+
+    subject { get :edit, params: { id: announcement.id } }
+
+    context "user signed in" do
+      before(:each) { sign_in(user) }
+
+      it "renders the edit template" do
+        subject
+        expect(response).to render_template(:edit)
+      end
+    end
+  end
+
+  describe "#update" do
+    let :announcement_params do
+      {
+        content: "The trebuchet is the superior siege weapon"
+      }
+    end
+
+    let! :announcement do
+      Announcement.create(content: "Dogs are pretty cool, I guess",
+                          starts_at: Time.current + 3.days,
+                          ends_at: Time.current + 10.days,
+                          user: user)
+    end
+
+    subject do
+      patch :update, params: {
+        id: announcement.id,
+        announcement: announcement_params
+      }
+    end
+
+    context "user signed in" do
+      before(:each) { sign_in(user) }
+
+      it "updates the announcement" do
+        subject
+        updated = Announcement.find announcement.id
+        expect(updated.content).to eq(announcement_params[:content])
+      end
+
+      it "redirects to announcement#index" do
+        subject
+        expect(response).to redirect_to(:announcement_index)
+      end
+    end
+  end
+
+  describe "#destroy" do
+    let! :announcement do
+      Announcement.create(content: "Dogs are pretty cool, I guess",
+                          starts_at: Time.current + 3.days,
+                          ends_at: Time.current + 10.days,
+                          user: user)
+    end
+
+    subject { delete :destroy, params: { id: announcement.id } }
+
+    context "user signed in" do
+      before(:each) { sign_in(user) }
+
+      it "deletes the announcement" do
+        expect { subject }.to change { Announcement.count }.by(-1)
+      end
+
+      it "redirects to announcement#index" do
+        subject
+        expect(response).to redirect_to(:announcement_index)
+      end
+    end
+  end
+end
+