Hoppa till huvudinnehåll

Hur man testar Unity spara migrationer mot historiska spelare stater

Ursprungliga Persistium-migrationsgraf som visar historiska räddningskontroller, transformationssteg och inspekterade resultat.

En praktisk, lokal-första process för att repetera Unity spara migrationer mot verkliga historiska statliga former innan en uppdatering når spelare.

Clean-account testning missar den viktiga defekten

En ny Unity-byggnad kan se perfekt ut när den börjar med en tom profil. Ett nytt konto har inga pensionerade fält, halvfärdiga uppdrag, cachade katalogreferenser, gamla lagerstackar, avbrutna inköp eller värden som var giltiga under en tidigare regelverk. Det bevisar därför bara att det nya formatet kan skapa ett nytt tillstånd. Det säger mycket lite om huruvida spelet säkert kan bära en spelare från gårdagens värld till dagens en.

Migrationsarbetet bör börja från en starkare fråga: kan detta exakta historiska tillstånd träda in i den nuvarande byggnaden, bevara den mening som fortfarande spelar roll, och antingen bli giltigt aktuellt tillstånd eller misslyckas på ett sätt som är användbart att diagnostisera? Det är en produktfråga så mycket som en serialiseringsfråga. Ett fält kan deserialisera framgångsrikt medan det fortfarande bryter mot en progressionsregel, pekar på saknad innehåll eller ändrar en köprätt.

Denna artikel beskriver en lokal-första repetition process. Det är medvetet inte ett löfte om att ett verktyg kan förstå varje Unity serialisering setup, backend eller plattform integration. Unity data modeller varierar, och ett spel kan lägga sin egen kryptering, moln synkronisering, binärt format eller anpassade adaptrar. Den hållbara delen är testdisciplin: bevara historiska former, kopiera dem innan mutation, göra migrationsvägen explicit, och kontrollera spelinvarianter efter varje gräns.

Bygg en historisk stat corpus

Behandla gamla sparar som en versionerad corpus, inte som lösa filer som passerade i chatt. Varje fixtur behöver en stabil identifierare, den version som producerade den, en kort scenikett, en formatdeklaration och en sekretessklassificering. Scenarieetiketten är viktigt eftersom en migrationspaket bör innehålla meningsfulla stater, inte bara slumpmässigt JSON. Exempel inkluderar en ny spelare, en spelare vid en kapitelgräns, en inventering vid dess stackgräns, en avbruten handledning, en gammal händelsebelöning, en användare med valfritt kosmetiskt innehåll, och en profil som innehåller en kombination.

Använd oföränderliga arbetskopior. Testköraren ska aldrig överskriva källfixturen medan du försöker en migrering. Kopiera fixturen till en tillfällig arbetskatalog, spela in sin checksumma eller innehålls hash, köra adaptern och behålla den resulterande utgången separat. Detta gör ett överraskande resultat till bevis som någon annan kan spela om. Det hindrar också ett test från att tyst förbättra sin egen inmatning tills det ursprungliga problemet försvinner.

Förvara inte spelardata från produktion i en allmänt tillgänglig katalog med testdata för utveckling. En historisk testdatasamling kan vara syntetisk, användas med samtycke, vara noggrant maskerad eller genereras utifrån deterministiska scenarier. Det viktiga är att den behåller de strukturella och semantiska gränsfall som spelar roll. Integritet får inte vara en eftertanke: ta bort direkta identifierare, enhetsidentifierare, kontaktuppgifter, betalningstoken, obearbetade kvitton och hemligheter innan testdata blir brett tillgängliga.

Rita migrationsdiagrammet innan du skriver en konverterare

Versionsnummer är inte en migrationsplan. Ett spel kan flytta från 1 till 2, 2 till 3, och 3 till 4, sedan stöter på en spelare som har hoppat direkt från 1 till 4. Det kan skicka ett hotfix som bara ändrar ett förfallsinventeringsrekord eller ett fält som gammalt innehåll fortfarande förväntar sig.

För varje stödd startversion, besluta om spelkedjor intilliggande omvandlar, använder en direkt omvandling, eller kräver en service-side uppgradering innan klienten laddar. Lämna inte hoppade versioner till vad som än händer när fälten är frånvarande. En kedja kan vara säkrare när varje steg är liten och testad. En direkt omvandling kan vara säkrare när mellanliggande format aldrig var avsedda att vara observerbara. Båda metoder behöver tydlig ägande och repeterbara fixturer.

Ursprunglig migrationsgraf med fem statsnoder kopplade av explicita stödda omvandlingsvägar.
En migrationsgraf gör version hoppar, stöds vägar och inspektionspunkter synliga innan koden döljer dem.

Grafen bör innehålla mer än den serialiserade typen. Record innehållskatalogberoende, konfigurationsversioner, funktionsflaggor som påverkar tolkning, och den aktuella applikationsversionen. En spara kan vara syntaktiskt aktuell men ogiltig eftersom en refererad artikel inte längre existerar eller en regel ändrad mening. De är kompatibilitetsgränser, inte irriterande kant fall.

Gör sparande runda resor observerbara

När en fixtur går in i migrationsvägen, utför en fullständig rundtur: ladda den historiska ingången, migrera den, konstruera in-game-modellen, spara den med den nuvarande författaren, ladda sedan den aktuella utgången igen. Den första belastningen kontrollerar om en historisk rekord kan komma in i systemet. Den andra belastningen kontrollerar om den nuvarande författaren skapade ett stabilt, självkonsekvent resultat. Jämför staten efter den första och andra belastningen enligt semantiska regler, inte bara rå byte jämlikhet.

Rå jämlikhet är ofta fel påstående. Nya standarder kan läggas till, fältorder kan ändras, tidsstämplar kan uppdateras, och samlingar kan få stabil beställning. Definiera en normalizer för värden som avsiktligt är icke-semantiska, jämföra sedan resten. Normalizer själv förtjänar granskning; det får inte bli en filt ignorera lista som döljer verklig förlust. En bra jämförelse rapporter som fälten tillsattes, avlägsnades, omvandlas, eller avsiktligt ignoreras.

Testresultatet bör namnge det första ogiltiga tillståndet. Om en migrationskedja har tre övergångar, rapportera inte bara att den slutliga belastningen misslyckades. Fånga staten efter varje kontrollpunkt, validera den och stanna vid den tidigaste gränsen som bryter mot en invariant. Att lokaliseringen omvandlar en vag "gamla sparade" rapport till en specifik migrationskant, fixtur och statlig skillnad.

Express spelspecifika invarianter

En allmän migrationssele kan inte veta vad progression betyder i ett visst spel. Spelet måste ge sina egna invarianter. Skriv dem på språk som ansluter till spelarens resultat: en nivå ligger inom det aktuella intervallet; en inventeringsmängd är icke-negativ och bunden; varje ägt objekt har en känd definition eller en explicit arvsnedgång; en färdig handledning förblir klar; valuta är ändlig; en sökreferens hör till en aktuell katalog; en rättighet är unik; en världsfrö och genererad världsstat håller med om.

Separata invarianter i lager. Strukturella invarianter svarar om det behövs fält och typer finns. Referentiella invarianter svarar om IDs pekar på kända definitioner. Domain invariants svarar om värdena lyder spelets regler. Säkerhetsinvarianter svarar om data är ändliga, bundna och säkra att visa. När en fixtur misslyckas, berättar lagret för laget om det behöver en serializer förändring, katalogadapter, regelbeslut eller återhämtningspolicy.

Använda deterministiska mutationer för att göra corpus arbete hårdare. Börja från en känd fixtur och avsiktligt ta bort ett fält, duplicera ett lager ID, ersätta en katalog referens, hoppa över en version, ordna en åtgärdslista, eller ändra en gränsmängd. Varje mutation bör ha ett förväntat resultat: migrera med en dokumenterad standard, avvisa med en diagnostisk kategori, karantän för återhämtning, eller kräva en ägargodkänd datareparation. "Det är inte krasch"

Minska ett misslyckande spara utan att förlora buggen

Stora spelarstater är svåra att förstå. Om en fixtur innehåller hundratals fält och en migration misslyckas, kan en utvecklare spendera timmar med att läsa orelaterade data. Counterexample minimering minskar fixturen samtidigt bevara den kränkta invarianten. Ta bort en fältgrupp, fördröja samma deterministiska migration och hålla borttagningen endast när misslyckandet fortfarande inträffar. Sedan partitionssamlingar, krymper värden mot gränser och minskar handlingshistoriken om replay beteenden ärenden.

Original counterexample-reduction visuell visar ett stort tillstånd begränsat genom repeterbara partitioner i en minimal regression fixtur.
Reduktionsprocessen bevarar det invarianta misslyckandet samtidigt som det avlägsnar orelaterade tillståndet.

Minskning kräver reproducerbarhet. Lås fixtur hash, migration version, adapter version, deterministiskt frö, relevant konfiguration ögonblicksbild, och förväntat invariant. Om miljön ändras under varje retry, en reducerare kan producera ett mindre tillstånd för ett annat problem. Håll en replay manifest med dessa ingångar och observerade resultat. Utgången är inte bara en mindre fil; det är ett regressionsfall någon annan kan utföra.

Genererade regressionsarmaturer bör ange samma granskningsväg som handauktoriserade. Ge varje fixtur ett stabilt namn, en kort förklaring av misslyckandet, den oföränderliga den bevarar och en förväntad klassificering. En regressionsarmatur är värdefull eftersom den gör en tidigare överraskande gränsrutin. Det bör inte bli en dold källa till produktionsspelare data eller en catch-all för oförklarliga misslyckanden.

Sätt repetitionen i CI utan att göra det bullrigt

Kör en snabb representativ delmängd på varje relevant förändring: nuvarande migrationskanter, högriskhistoriska stater och en liten uppsättning av deterministiska mutationer. Kör hela corpus på ett schemalagt jobb, släpp kandidat eller förändring som berör serialisering, progression, katalogtolkning, molnsynkronisering eller räddningsformat kod. Shard by fixture family or migration edge i stället för att skicka varje test genom en lång sekvens.

CI-utgången bör vara kortfattad men inspekterbar. Rapportera fixtur-ID, start- och målversioner, migrationskant, invariant skikt, första ogiltig kontrollpunkt och en väg till den redigerade artefakten eller diff. Undvik att skriva ut fullprofilinnehåll i loggar. När ett misslyckande är nytt, behåll den minimala informationen som behövs för att reproducera den lokalt; när det förväntas, spela in den klassificeringen så att en release inte tyst normaliserar en känd risk.

Utgivningsbeslutet bör ange vad bevisen betyder. Passera migrationstest stöder ett begränsat påstående: den testade corpus och deklarerade vägar som bete sig som förväntat i den miljön. De bevisar inte att varje spelare sparar, enhet eller extern tjänst kommer att bete sig identiskt. Teams behöver fortfarande rullningsplaner, kundstödshantering och övervakning av den respekten för integriteten.

Praktisk checklista

  • Håll en versionerad historisk corpus med scenetiketter och sekretessklassificeringar.
  • Kopiera ingångar före migration och bevara hash för käll- och utgångsartefakter.
  • Rita stödda migrationskanter, inklusive skipped-version politik och explicit avslag.
  • Validera strukturella, referentiella, domän- och säkerhetsinvarianter efter varje kontrollpunkt.
  • Round-trip migrerade utgången genom den nuvarande författaren och läsaren.
  • Använda deterministiska mutationer för att testa saknade fält, dubbla poster, pensionerat innehåll och gränsvärden.
  • Minska reproducerbara misslyckanden i granskade regressionsarmaturer med replay manifest.
  • Kör riskfokuserade delmängder kontinuerligt och hela corpus innan releasekänsliga förändringar.
  • Håll loggar och artefakter redigerade; vrid inte CI till ett arkiv för spelardata.

Ofta ställda frågor

Behöver vi riktiga spelare sparar för att testa migration?

Nej. Riktiga historiska former är användbara, men corpus kan vara syntetiska eller försiktigt redigerade. Vad som är viktigt är att bevara de svåra statliga kombinationerna: pensionerat innehåll, lång progression, avbrutna övergångar, valfria data och värden till meningsfulla gränser. Om produktionsdata används för att upptäcka en kant fall, härleda en säker fixtur som bara behåller fastigheten under test.

Skulle varje gammal version vara stödd för alltid?

Stöd är inte nödvändigtvis ett produkt- och operativt beslut. Det viktiga är att göra gränsen explicit: vilka versioner migrerar, som kräver en tidigare uppdatering, som avvisas, och hur spelaren informeras. En odokumenterad oavsiktlig väg är det minst säkra alternativet eftersom det varken tillförlitligt stöds eller tydligt vägras.

Kan ett serializer-test ersätta gameplay-test?

Nej. Serializer tester fastställer att data kan läsas och skrivas enligt deklarerade former. Gameplay och domäntester fastställer att den resulterande staten är meningsfull i den nuvarande regeln. En robust migration repetition behöver både, plus en översyn av innehåll och konfigurationsreferenser som påverkar betydelsen av sparade värden.

Vad är Persistium roll här?

Persistium är en lokal-första tillförlitlighet produktfamilj. Vägledningen i denna anteckning är praktisk teknisk rådgivning, inte ett påstående att en offentlig Persistium-produkt är tillgänglig eller att den har diagnostiserat riktiga kunddata. Dess kontinuitetsriktning utforskar den typ av explicit migration, replay, jämförelse och reduktion arbetsflöde som beskrivs ovan.

Relaterat systemUtforska Persistium