Skip to content

SmartReplaceObjects: ImportAsset(ForceSynchronousImport) no longer reliable after PR#2 test ordering shift #6

Description

@Scaler0222

Background

SelectionDrivenSkillTests.SmartReplaceObjects_ReplacesSelectedObjectsWithPrefab flakes on Unity 6000.5.0b8 + URP 17.5. Failure mode: Expected: "success" / But was: "error" at SelectionDrivenSkillTests.cs:137 — the smart_replace_objects skill returns an error envelope because AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath) (inside the skill body) returns null even after the test's prefab SaveAsPrefabAsset call.

PR#1 (#3) added a one-line guard at SelectionDrivenSkillTests.cs:129:

PrefabUtility.SaveAsPrefabAsset(sourcePrefabGo, prefabPath);
Object.DestroyImmediate(sourcePrefabGo);
AssetDatabase.ImportAsset(prefabPath, ImportAssetOptions.ForceSynchronousImport);

That fix was sufficient at PR#1 verification time (test passed cleanly).

PR#2 (#5) added 3 new tests in sibling fixtures (SkillsModeManagerTests.CurrentMode_ExplicitAutoPref_…, …CurrentMode_MigrationMatrix_AllThreeBranchesHonorIntent, SkillValidationTests.Execute_UnknownParamErrorEnvelope_PreservesNestedDetailsPath_ForLegacyClients). The new tests don't touch any Smart code path, but they're enough to shift NUnit's test-discovery order so that something running before SmartReplaceObjects_… leaves the AssetDatabase in a state where ForceSynchronousImport no longer reliably stabilizes the import.

Observed in 3 of 4 post-PR#2 verification runs.

Root cause hypothesis

Unity 6 import pipeline is genuinely async — the worker is a separate process, and AssetDatabase.LoadAssetAtPath<GameObject> reads from the imported-asset cache (not raw disk). On 6000.5.0b8, ImportAssetOptions.ForceSynchronousImport blocks until the import message is processed, but if the worker is mid-flight on a prior test's prefab (or scene save) the synchronization isn't atomic across the Save → Import → Load chain.

The Smart skill body (SmartSkills.cs:516-537) does not retry on null load — first miss → "Prefab not found" envelope → test fails.

Recommended fix

Test-side hardening — wrap save-and-load in a small retry loop in SelectionDrivenSkillTests.cs:

var prefabPath = Path.Combine(TempRoot, "Replacement.prefab").Replace('\', '/');
PrefabUtility.SaveAsPrefabAsset(sourcePrefabGo, prefabPath);
Object.DestroyImmediate(sourcePrefabGo);

// Belt-and-suspenders for Unity 6.x async import: flush, refresh, then
// wait for the prefab to actually appear in the imported-asset cache.
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
AssetDatabase.ImportAsset(prefabPath, ImportAssetOptions.ForceSynchronousImport);
for (var attempt = 0; attempt < 5 && AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath) == null; attempt++)
{
    System.Threading.Thread.Sleep(50);
    AssetDatabase.ImportAsset(prefabPath, ImportAssetOptions.ForceSynchronousImport);
}
Assert.That(AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath), Is.Not.Null,
    "Prefab must be visible in the imported-asset cache before the skill is called");

Alternative: harden the skill itself in SmartSkills.SmartReplaceObjects with a single retry-on-null. That's a bigger contract change for the production skill and not preferred — the test environment is the brittle thing.

Acceptance criteria

  • SmartReplaceObjects_ReplacesSelectedObjectsWithPrefab passes on 50/50 consecutive EditMode runs on Unity 6000.5.0b8 + URP 17.5.
  • No change to Editor/Skills/SmartSkills.cs.
  • No change to other passing SelectionDrivenSkillTests cases.

Context

Surfaced during PR#2 (#5) verification of issue #1. PR#1 ImportAsset fix is still in place — needed but not sufficient under the new NUnit ordering. Tracking separately so PR#3 (ShaderGraph) can ship.

Refs: #1
Related: #3 (PR#1, added the initial ImportAsset guard), #5 (PR#2, added the test additions that shifted ordering)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions