DEV Community

Dutchskull
Dutchskull

Posted on

Setting Up Unit Testing in an Existing Unity Project

If you’re knee-deep in a Unity project and pulling your hair out trying to set up unit testing, you’re not alone. The two biggest challenges are dealing with Assembly Definitions and Editor folders. Here’s a guide to overcome these issues and make your life easier.

The Problem

Unity, in its infinite wisdom, doesn’t allow writing tests on the default Assembly-CSharp and Assembly-CSharp-Editor assemblies. Frustrating, right?

Image description

To fix this, you need to add Assembly Definitions for both your game code and editor code. Here’s how:

  1. Game Code:

    • Add an Assembly Definition at the root of your project.
    • Update the dependencies in the Inspector until there are no compiler errors. Off to the races!
  2. Editor Code:

    • Here’s where it gets tricky. In a big project, you’ll have lots of external dependencies and plugins, some with Assembly Definitions, some without.
    • Without Assembly Definitions, Unity sees these Editor folders as game code and tries to build them into your final game, which inevitably fails.

The Solution

  1. Create a Top-Level Editor Folder:

    • At the top level of your project, create an Editor folder.
    • Add an Assembly Definition inside this folder. Name it similarly to your game code Assembly Definition but with a .Editor postfix (or whatever you prefer).
  2. Link Editor Folders:

    • For each Editor folder in your project, create an Assembly Definition Reference and link it to the top-level Editor folder Assembly Definition.
    • This process can be incredibly tedious in a large project, so here’s a Python script to save you from hours of mind-numbing work:
import os
import json
import yaml

def get_guid_from_meta(meta_file_path):
    with open(meta_file_path, 'r') as meta_file:
        meta_content = yaml.safe_load(meta_file)
    return meta_content.get('guid')

def create_reference_json(editor_path, source_file_name, guid):
    json_content = {
        "reference": "GUID:" + guid
    }
    asmref_file_name = os.path.splitext(source_file_name)[0] + '.asmref'
    json_file_path = os.path.join(editor_path, asmref_file_name)
    with open(json_file_path, 'w') as json_file:
        json.dump(json_content, json_file, indent=4)
    print(f"Created {json_file_path} with GUID reference.")

def copy_file_to_editor_folders(unity_project_path, source_file):
    if not os.path.isdir(unity_project_path):
        print(f"The project path {unity_project_path} does not exist.")
        return

    meta_file_path = source_file + '.meta'
    if not os.path.isfile(meta_file_path):
        print(f"The meta file {meta_file_path} does not exist.")
        return
    guid = get_guid_from_meta(meta_file_path)

    source_file_name = os.path.basename(source_file)

    for root, dirs, files in os.walk(unity_project_path):
        if 'Editor' in dirs:
            editor_path = os.path.join(root, 'Editor')
            asmdef_exists = any(file.endswith('.asmdef') for file in os.listdir(editor_path))

            if not asmdef_exists:
                create_reference_json(editor_path, source_file_name, guid)
            else:
                print(f"A .asmdef file already exists in the folder {editor_path}.")

# Example usage
unity_project_path = r"PATH\TO\ASSETS\FOLDER"
source_file = r"PATH\TO\Editor.asmdef"

copy_file_to_editor_folders(unity_project_path, source_file)
Enter fullscreen mode Exit fullscreen mode

This script requires pyyaml to run:

pip install pyyaml
Enter fullscreen mode Exit fullscreen mode
  • Set unity_project_path to your Unity project’s assets folder.
  • Set source_file to the path of your Editor Assembly Definition.

The script will:

  • Crawl your project for all Editor folders.
  • Check if an Assembly Definition is present.
  • Add an Assembly Definition Reference if none exists.

After setting this up, follow the Unity Testing Framework tutorial to start writing tests.

Additional Tips

Consider splitting your code with Assembly Definitions to create logical boundaries and improve maintainability. It might be a pain now, but your future self will thank you!

Happy testing!

Top comments (0)