[英]Deleting test database in Vapor 3
我想為 Vapor 3 服務器編寫一些集成測試,並且每次運行測試時我都需要擁有干凈的 Postgre 數據庫。 我怎樣才能做到這一點? 如果數據庫尚不存在,遷移似乎不是正確的方法,因為它們已經運行過一次。
看看https://github.com/raywenderlich/vapor-til/tree/master/Tests
這需要在運行測試之前運行一個數據庫,但它會在每次測試運行開始時恢復所有遷移,從而每次都為您提供一個干凈的數據庫。 (具體在這里)
根目錄中還有一個docker-compose.yml
用於在 Linux 上啟動一個完全隔離的測試環境
我找到了一個資源密集度較低的解決方案,然后每次都恢復所有遷移。
RSpec 有一個配置( use_transactional_fixtures
),允許將每個測試包裝在 SQL 事務中。 測試結束后,它將回滾事務,從而恢復測試期間發生的所有更改。 相關文檔在這里。
我們可以在 Vapor 中實現類似的解決方案。 我的示例測試如下所示。
final class VaporTests: XCTestCase {
var app: Application!
override func setUp() {
super.setUp()
app = try! Application.buildForTesting()
let conn = try! app.requestPooledConnection(to: .psql).wait()
try! conn.simpleQuery("BEGIN TRANSACTION").wait()
try! app.releasePooledConnection(conn, to: .psql)
}
override func tearDown() {
let conn = try! app.requestPooledConnection(to: .psql).wait()
try! conn.simpleQuery("ROLLBACK").wait()
try! app.releasePooledConnection(conn, to: .psql)
super.tearDown()
}
func testExample() throws {
let request = HTTPRequest(method: .GET, url: "my/endpoint/example")
let wrapper = Request(http: request, using: app)
let response = try ExampleController().example(wrapper).wait()
XCTAssertEqual(response, .ok)
}
}
為了確保我不會遇到並發問題,我將測試應用程序中的數據庫池限制為 1 個連接。
func configure(_ config: inout Config, _ env: inout Environment, _ services: inout Services) throws {
// ... other configurations
let poolConfig = DatabaseConnectionPoolConfig(maxConnections: 1)
services.register(poolConfig)
}
非常感謝Jakub Jatczak幫助我了解這在 Rails 中是如何發生的。
參加聚會很晚,但按照以下方式進行revert
和migrate
命令工作。 此代碼執行與@0xTim 給出的答案類似的命令。 但我已經使用了Console.framework
:
大多數情況下,我們使用如下所示的configure.swift
文件:
import FluentPostgreSQL
import Vapor
public func configure(_ config: inout Config, _ env: inout Environment, _ services: inout Services) throws {
// Register providers first
try services.register(FluentPostgreSQLProvider())
...
/// Configure commands
var commandConfig = CommandConfig.default()
commandConfig.useFluentCommands()
services.register(commandConfig)
...
/// Configure migrations
services.register { container -> MigrationConfig in
var migrationConfig = MigrationConfig()
try migrate(migrations: &migrationConfig)
return migrationConfig
}
}
聚會很晚,但以下代碼確實執行了恢復和遷移命令:(我使用Quick
和Nimble
所以beforeSuite
。注釋代碼在那里,因為除非您使用上面的configure.swift
否則您可以取消注釋代碼並直接使用CommandConfig
。 )
import Quick
import Vapor
import Console
import FluentPostgreSQL
...
configuration.beforeSuite {
let console: Console = Terminal()
// var commandConfig = CommandConfig()
// commandConfig.use(RevertCommand(), as: "revert")
// commandConfig.use(MigrateCommand(), as: "migrate")
var config = Config.default()
var env = Environment.testing
var services = Services.default()
do {
// try App.configure(&config, &env, &services)
let container = try Application(config: config, environment: env, services: services)
let commandConfig = try container.make(CommandConfig.self)
let commands = try commandConfig.resolve(for: container).group()
var input = CommandInput(arguments: ["vapor","revert","--all", "-y"])
try console.run(commands, input: &input, on: container).wait()
input = CommandInput(arguments: ["vapor","migrate","-y"])
try console.run(commands, input: &input, on: container).wait()
} catch let error {
console.error(error.localizedDescription)
exit(1)
}
}
對於那些正在尋求另一種不涉及注冊新遷移的方法(對我來說,增加更多代碼復雜性)的人,您可以使用Pre-Action腳本作為測試目標( ⌘ + < )
通過使用 bash 腳本,您可以創建一個全新的 postgresql 數據庫,該數據庫將用於構建僅用於測試的項目:
# Variables
export IS_TEST=true
export DB_USERNAME="`whoami`"
export DB_DBNAME="BARTENDER_TEST_DB"
#Creating dedicated Postgres DB
echo "deleting & recreating $DB_DBNAME for user $DB_USERNAME"
psql postgres<< EOF
DROP DATABASE "$DB_DBNAME";
CREATE DATABASE "$DB_DBNAME";
\list
EOF
然后在configure.swift
文件中創建一個與新創建的數據庫匹配的PostgreSQLDatabaseConfig
if let _ = Environment.get("IS_TEST") { // IS_TEST is defined only in Pre-Action script
guard let username = Environment.get("DB_USERNAME") else {
fatalError("Failed to create PostgresConfig - DB_USERNAME in Environment variables")
}
guard let databasename = Environment.get("DB_DBNAME") else {
fatalError("Failed to create PostgresConfig - DB_DBNAME in Environment variables")
}
postgresqlConfig = PostgreSQLDatabaseConfig(
hostname: "127.0.0.1",
port: 5432,
username: username,
database: databasename,
password: nil
)
}
else { /* your other config here */ }
let database = PostgreSQLDatabase(config: postgresqlConfig)
...
我在這方面發現的最大優勢是,我什至vapor run
從另一個項目中觸發vapor build
和vapor run
,這將為我的持續集成測試創建一個全新的 Web 服務環境,只需插入正確的環境變量
我發現的最簡單的方法是將PostgresKit添加到測試目標並使用它來設置連接以調用我的“清理”查詢。
@testable import App
import Vapor
import XCTest
import PostgresKit
final class UserTests: XCTestCase {
var pools: EventLoopGroupConnectionPool<PostgresConnectionSource>!
var postgresDb: PostgresDatabase!
var eventLoopGroup: EventLoopGroup!
override func setUp() {
let configuration = PostgresConfiguration(
hostname: "localhost",
username: "postgres",
password: "password",
database: "db_name"
)
eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 2)
pools = EventLoopGroupConnectionPool(
source: PostgresConnectionSource(configuration: configuration),
on: eventLoopGroup
)
postgresDb = pools.database(logger: Logger.init(label: "TestLogger"))
}
override func tearDown() {
let _ = try! postgresDb.query("DELETE FROM \(User.schema)").wait()
try! pools.syncShutdownGracefully()
try! eventLoopGroup.syncShutdownGracefully()
}
func testUploadUser() throws {
let app = Application(.testing)
defer { app.shutdown() }
try configure(app)
try app.testable(method: .running).test(.POST, "api/users", beforeRequest: { req in
try req.content.encode(["firstName" : "Dwide", "lastName" : "Shrewd"])
}, afterResponse: { res in
XCTAssertEqual(res.status, .ok)
let user = try res.content.decode(User.self)
XCTAssertEqual(user, User(id: user.id, firstName: "Dwide", lastName: "Shrewd"))
})
}
}
這是我的Package.swift
// swift-tools-version:5.2
import PackageDescription
let package = Package(
name: "MyVaporProject",
platforms: [
.macOS(.v10_15)
],
dependencies: [
// 💧 A server-side Swift web framework.
.package(url: "https://github.com/vapor/vapor.git", from: "4.0.0"),
.package(url: "https://github.com/vapor/fluent.git", from: "4.0.0"),
.package(url: "https://github.com/vapor/fluent-postgres-driver.git", from: "2.0.0"),
.package(url: "https://github.com/vapor/postgres-kit.git", from: "2.0.0")
],
targets: [
.target(
name: "App",
dependencies: [
.product(name: "Fluent", package: "fluent"),
.product(name: "FluentPostgresDriver", package: "fluent-postgres-driver"),
.product(name: "Vapor", package: "vapor")
],
swiftSettings: [
// Enable better optimizations when building in Release configuration. Despite the use of
// the `.unsafeFlags` construct required by SwiftPM, this flag is recommended for Release
// builds. See <https://github.com/swift-server/guides#building-for-production> for details.
.unsafeFlags(["-cross-module-optimization"], .when(configuration: .release))
]
),
.target(name: "Run", dependencies: [.target(name: "App")]),
.testTarget(
name: "AppTests",
dependencies: [
.target(name: "App"),
.product(name: "XCTVapor", package: "vapor"),
.product(name: "PostgresKit", package: "postgres-kit")
]
)
]
)
與之前的答案一樣,這需要一個獨立的 Postgres 數據庫,已經遷移,准備在測試開始之前進行連接。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.