Para dar a cada cenário seu próprio resultado e controle de nova execução no Xcode, migre um teste unitário do XCTest baseado em loop para o @Test parametrizado do Swift Testing. Este passo a passo usa um cálculo local de layout de blocos para mostrar a migração e verificar seu comportamento nos relatórios.
Por que um loop do XCTest não informa cada cenário separadamente?
O XCTest descobre métodos de teste em uma subclasse de XCTestCase. Esses métodos não recebem parâmetros e têm nomes que começam com test. Um loop dentro de um método descoberto continua fazendo parte desse método; suas iterações não se tornam testes descobertos separadamente. Adicionar o nome de um cenário a uma asserção pode melhorar o diagnóstico, mas não cria um controle de execução individual. Consulte Defining Test Cases and Test Methods, da Apple.
O ciclo de vida segue o mesmo limite. O XCTest executa os métodos de configuração da instância antes de cada método de teste e os métodos de desmontagem depois dele. Portanto, um loop com cinco iterações não recebe automaticamente cinco ciclos de configuração e desmontagem. Se uma iteração alterar uma fixture, a próxima poderá herdar esse estado, a menos que o teste o redefina explicitamente. A Apple documenta essa sequência em Set Up and Tear Down State in Your Tests.
O Swift Testing oferece o resultado necessário aqui: uma função aceita argumentos de cenário, e o executor trata suas invocações como casos independentes. O Xcode exibe os argumentos e oferece controles de execução individuais. A Apple demonstra esse comportamento em Go further with Swift Testing.
Essa distinção importa ao diagnosticar falhas. Uma falha de asserção e uma saída antecipada são eventos diferentes: um loop pode continuar verificando após uma asserção comum, enquanto um erro lançado ou um return explícito pode impedir a execução das iterações seguintes. Separar os cenários em casos elimina esse fluxo de controle compartilhado entre eles. Isso não torna recuperável uma falha que encerra o processo.
Prepare o destino de testes unitários existente
Use o Xcode 16 ou posterior neste fluxo de trabalho. O Swift Testing está incluído nessas distribuições do Xcode e nas toolchains do Swift.org a partir do Swift 6.0. O projeto Swift recomenda usar a versão incluída para tarefas comuns de teste; este exemplo não precisa de nenhuma dependência de pacote externo. Consulte Obtaining Swift Testing.
Mantenha o bundle de testes unitários existente. A Apple oferece suporte explícito ao Swift Testing e ao XCTest no mesmo destino, então uma migração gradual pode começar com um único arquivo Swift novo. No Xcode, escolha File > New > New File From Template, selecione Swift Testing Unit Test e adicione o arquivo ao destino de testes unitários existente. Se o projeto não tiver um destino de testes, crie um Unit Testing Bundle em File > New > Target. Essas etapas estão documentadas em Adding tests to your Xcode project.
Este passo a passo testa diretamente o código de cálculo. Ele não automatiza uma janela da área de trabalho. O caminho documentado pela Apple para automação de interface continua usando o XCTest; use esta abordagem parametrizada para a lógica subjacente que determina o layout. O mesmo guia para adicionar testes descreve essa distinção entre frameworks.
Transforme cada cenário em um registro completo de argumentos
Suponha que um app para Mac organize blocos em linhas. Com quatro colunas, zero blocos exige zero linhas, quatro blocos preenchem uma linha e cinco blocos exigem duas linhas. A tarefa concreta é preservar essas verificações e, ao mesmo tempo, tornar cada cenário visível e executável de forma independente.
Use um único registro que contenha o nome do cenário, as entradas e a saída esperada. Assim, o resultado esperado permanece vinculado à sua entrada quando casos são adicionados ou reordenados. Os cinco registros a seguir são dados de teste ilustrativos, não observações de um aplicativo existente.
| Cenário | Quantidade de blocos | Colunas | Linhas esperadas | Finalidade |
|---|---|---|---|---|
empty |
0 | 4 | 0 | Entrada vazia |
one-tile |
1 | 4 | 1 | Primeira linha incompleta |
exact-row |
4 | 4 | 1 | Limite exato |
wrap |
5 | 4 | 2 | Primeiro bloco além do limite |
two-full-rows |
8 | 4 | 2 | Múltiplo exato |
Coloque este arquivo completo e autocontido no destino de testes unitários. Ele inclui uma implementação sintética para que possa ser experimentado sem um módulo de app ou outros arquivos. Não usa serviços, mocks, arquivos nem acesso à rede.
import Testing
private struct TileLayout {
func rowCount(tileCount: Int, columns: Int) -> Int {
precondition(tileCount >= 0)
precondition(columns > 0)
let fullRows = tileCount / columns
let partialRow = tileCount % columns == 0 ? 0 : 1
return fullRows + partialRow
}
}
private struct LayoutScenario:
Codable, Sendable, CustomTestStringConvertible {
let name: String
let tileCount: Int
let columns: Int
let expectedRows: Int
var testDescription: String { name }
static let examples: [LayoutScenario] = [
.init(name: "empty", tileCount: 0,
columns: 4, expectedRows: 0),
.init(name: "one-tile", tileCount: 1,
columns: 4, expectedRows: 1),
.init(name: "exact-row", tileCount: 4,
columns: 4, expectedRows: 1),
.init(name: "wrap", tileCount: 5,
columns: 4, expectedRows: 2),
.init(name: "two-full-rows", tileCount: 8,
columns: 4, expectedRows: 2)
]
}
struct TileLayoutTests {
@Test("Tile rows", arguments: LayoutScenario.examples)
fileprivate func rowCountMatchesScenario(
_ scenario: LayoutScenario
) {
let layout = TileLayout()
let actualRows = layout.rowCount(
tileCount: scenario.tileCount,
columns: scenario.columns
)
#expect(actualRows == scenario.expectedRows)
}
}
A migração move a iteração para @Test(arguments:): cada elemento se torna o argumento de uma invocação. Codable fornece suporte à codificação para novas execuções seletivas, enquanto CustomTestStringConvertible fornece o rótulo legível do cenário. A Apple documenta a parametrização em Implementing parameterized tests e as descrições personalizadas dos argumentos em Go further with Swift Testing.
A fixture é criada deliberadamente dentro da função de teste. Cada invocação cria seu próprio TileLayout; nada depende de um cenário anterior. Se estiver migrando uma fixture existente, transfira sua configuração de forma deliberada, sem esperar que os hooks herdados do XCTest sejam executados. As suítes do Swift Testing não herdam de XCTestCase; a Apple associa a configuração a um inicializador e a desmontagem de classes ou atores a deinit em Migrating a test from XCTest.
O cálculo aceita quantidades de blocos não negativas e quantidades de colunas estritamente positivas. Suas precondições definem esse contrato; valores inválidos estão fora dos casos deste exemplo. Se o código real do aplicativo precisar retornar um erro recuperável para uma entrada inválida, altere esse contrato da API e adicione os testes correspondentes antes de ampliar esta tabela.
Confirme resultados separados e execute novamente um caso com falha
Execute a função parametrizada usando o losango ao lado de sua declaração. Em seguida, abra o Test navigator e expanda a função para inspecionar seus casos. Para executar um único caso, aponte para o losango desse caso e clique no controle de reprodução. Clicar no controle de reprodução da função pai executa todos os seus casos. A Apple documenta as duas ações em Running tests and interpreting results.
Para uma verificação controlada dos relatórios, altere temporariamente o expectedRows do registro wrap de 2 para 3. Execute a função parametrizada inteira. O resultado esperado é a execução de cinco casos, com falha na comparação wrap porque a implementação retorna 2. Selecione esse caso e execute-o novamente de forma individual; depois, restaure o valor esperado para 2. Essa é uma alteração deliberada dos dados de teste, não uma evidência de defeito na implementação.
Inspecione os detalhes Results e Arguments da expectativa que falhou para comparar o valor calculado com a entrada do cenário. Para a execução completa, abra View > Navigators > Reports, selecione a ação de teste e inspecione a seção Tests. Esses controles de inspeção estão descritos no guia de resultados de testes da Apple.
A execução seletiva tem um requisito adicional além de rótulos legíveis: o executor precisa identificar deterministicamente cada argumento. A documentação atual da Apple aceita CustomTestArgumentEncodable, certos tipos RawRepresentable, Encodable ou Identifiable com um identificador codificável. O registro Codable do exemplo atende à opção de codificação. Uma string de exibição personalizada, por si só, não atende a esse requisito. Consulte Implementing parameterized tests.
A aritmética esperada para os cinco registros foi verificada localmente com divisão inteira e resto em Python. Uma implementação incorreta ilustrativa que usa apenas divisão inteira arredondada para baixo falha em one-tile e wrap. O arquivo Swift foi inspecionado, mas não compilado neste ambiente de pesquisa porque o Swift não estava disponível; a execução no Xcode acima continua sendo a etapa de verificação executável.
Preserve a quantidade de casos e o ciclo de vida pretendidos
Uma verificação útil da migração compara três coisas: a quantidade de registros de cenário, os casos executados na execução completa e a possibilidade de executar sozinho um caso selecionado. Neste exemplo, a quantidade pretendida é cinco. Uma quantidade diferente deve levar à inspeção da criação de argumentos e da seleção de testes antes de alterar o cálculo.
Mantenha juntas as expectativas associadas. Passar duas coleções separadas para arguments: gera o produto cartesiano delas. Cinco entradas e cinco saídas esperadas produziriam, portanto, 25 combinações, em vez de cinco cenários correspondentes. Use coleções separadas quando todas as combinações forem relevantes; use registros ou zip() para dados associados. A Apple explica a diferença em Implementing parameterized tests.
Se estiver usando zip(), verifique os comprimentos das coleções antes de construir os pares: o Swift para na sequência mais curta. Caso contrário, um resultado esperado extra poderia ficar sem uso, sem gerar um caso. Um único registro de cenário evita esse tipo de incompatibilidade. O comportamento de truncamento está documentado na referência do Swift para zip(::).
A ordem de execução também muda a decisão de migração. Por padrão, o Swift Testing executa os casos em paralelo. Este exemplo tem argumentos imutáveis e uma fixture local, portanto, seus resultados não dependem da ordem. Para executar temporariamente em série uma função parametrizada, adicione .serialized ao atributo @Test. Aplicar essa característica a uma suíte também serializa os testes e casos nela contidos, mas não serializa suítes sem relação. Consulte Running tests serially or in parallel.
A execução em série não cria um estado novo nem estabelece um contrato de dependência entre cenários. Se um caso só funcionar depois que outro caso alterar alguma coisa, reformule sua preparação para que possa ser executado de forma independente. Se as etapas formarem intencionalmente uma única operação contínua, mantenha-as em um só teste e parametrize operações completas.
Use as asserções do Swift Testing em todo este exemplo migrado. Ao reutilizar helpers que contêm asserções do XCTest, verifique o comportamento de interoperabilidade da toolchain: o guia de migração atual da Apple documenta modos e padrões que variam conforme a toolchain e a versão das ferramentas do pacote. Manter este arquivo inteiramente dentro de Testing evita essa dependência. Consulte Migrating a test from XCTest.
Se a migração precisar esperar, a alternativa compatível no XCTest é ter um método de teste nomeado e sem parâmetros para cada cenário, com helpers compartilhados de cálculo e asserção, conforme apropriado. A Apple recomenda um teste para cada cenário em seu guia para adicionar testes. Isso preserva resultados separados por método sem exigir a parametrização do Swift Testing.
A conversão está concluída quando cada cenário original tem um caso executado correspondente, sua fixture começa no estado pretendido e um caso selecionado pode ser executado com sucesso por conta própria. Preserve as entradas de limite e as saídas esperadas durante essa alteração: os relatórios independentes são úteis porque facilitam localizar, diagnosticar e repetir essas verificações existentes.
Fontes
- Defining Test Cases and Test Methods — Apple
- Set Up and Tear Down State in Your Tests — Apple
- Go further with Swift Testing — Apple
- Obtaining Swift Testing — projeto Swift
- Adding tests to your Xcode project — Apple
- Implementing parameterized tests — Apple
- Migrating a test from XCTest — Apple
- Running tests and interpreting results — Apple
- zip(::) — Apple
- Running tests serially or in parallel — Apple