diff --git a/models/actions/main_test.go b/models/actions/main_test.go
new file mode 100644
index 000000000..5d5089e3b
--- /dev/null
+++ b/models/actions/main_test.go
@@ -0,0 +1,18 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package actions
+
+import (
+	"testing"
+
+	"code.gitea.io/gitea/models/unittest"
+)
+
+func TestMain(m *testing.M) {
+	unittest.MainTest(m, &unittest.TestOptions{
+		FixtureFiles: []string{
+			"action_runner_token.yml",
+		},
+	})
+}
diff --git a/models/actions/runner_token_test.go b/models/actions/runner_token_test.go
new file mode 100644
index 000000000..e85e99abe
--- /dev/null
+++ b/models/actions/runner_token_test.go
@@ -0,0 +1,40 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package actions
+
+import (
+	"testing"
+
+	"code.gitea.io/gitea/models/db"
+	"code.gitea.io/gitea/models/unittest"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestGetLatestRunnerToken(t *testing.T) {
+	assert.NoError(t, unittest.PrepareTestDatabase())
+	token := unittest.AssertExistsAndLoadBean(t, &ActionRunnerToken{ID: 3})
+	expectedToken, err := GetLatestRunnerToken(db.DefaultContext, 1, 0)
+	assert.NoError(t, err)
+	assert.EqualValues(t, token, expectedToken)
+}
+
+func TestNewRunnerToken(t *testing.T) {
+	assert.NoError(t, unittest.PrepareTestDatabase())
+	token, err := NewRunnerToken(db.DefaultContext, 1, 0)
+	assert.NoError(t, err)
+	expectedToken, err := GetLatestRunnerToken(db.DefaultContext, 1, 0)
+	assert.NoError(t, err)
+	assert.EqualValues(t, token, expectedToken)
+}
+
+func TestUpdateRunnerToken(t *testing.T) {
+	assert.NoError(t, unittest.PrepareTestDatabase())
+	token := unittest.AssertExistsAndLoadBean(t, &ActionRunnerToken{ID: 3})
+	token.IsActive = true
+	assert.NoError(t, UpdateRunnerToken(db.DefaultContext, token))
+	expectedToken, err := GetLatestRunnerToken(db.DefaultContext, 1, 0)
+	assert.NoError(t, err)
+	assert.EqualValues(t, token, expectedToken)
+}
diff --git a/models/fixtures/action_runner_token.yml b/models/fixtures/action_runner_token.yml
new file mode 100644
index 000000000..6520b7f6f
--- /dev/null
+++ b/models/fixtures/action_runner_token.yml
@@ -0,0 +1,35 @@
+-
+  id: 1 # instance scope
+  token: xeiWBL5kuTYxGPynHCqQdoeYmJAeG3IzGXCYTrDX
+  owner_id: 0
+  repo_id: 0
+  is_active: 1
+  created: 1695617748
+  updated: 1695617748
+
+-
+  id: 2 # user scope and can't be used
+  token: vohJB9QcZuSv1gAXESTk2uqpSjHhsKT9j4zYF84x
+  owner_id: 1
+  repo_id: 0
+  is_active: 0
+  created: 1695617749
+  updated: 1695617749
+
+-
+  id: 3 # user scope and can be used
+  token: gjItAeJ3CA74hNPmPPo0Zco8I1eMaNcP1jVifjOE
+  owner_id: 1
+  repo_id: 0
+  is_active: 1
+  created: 1695617750
+  updated: 1695617750
+
+-
+  id: 4 # repo scope
+  token: NOjLubxzFxPGhPXflZknys0gjVvQNhomFbAYuhbH
+  owner_id: 0
+  repo_id: 1
+  is_active: 1
+  created: 1695617751
+  updated: 1695617751