Avatar ·

Как получить путь к сборке (assembly), из которой выполняется текущий код?

Всем привет! Я начинающий C# разработчик, пишу небольшой проект для автоматизации тестирования с использованием MBUnit. У меня возникла проблема: мне нужно получить путь к файлу сборки (assembly), из которой выполняется текущий код. Зачем? Я хочу, чтобы тесты загружали тестовые данные из папки, расположенной рядом с исполняемым файлом тестов. Если я использую Environment.CurrentDirectory, то в разных средах (Visual Studio, консольный запуск, CI сервер) путь может отличаться, что приводит к ошибкам "файл не найден".

Вот пример кода, который я пробовал:

string path = Environment.CurrentDirectory;
Console.WriteLine($"Текущая директория: {path}");

Проблема в том, что при запуске тестов из MBUnit этот путь указывает на папку Visual Studio, а не на папку с тестовой сборкой. Я слышал, что можно использовать рефлексию, чтобы получить путь к самой сборке, но не понимаю, как это правильно сделать. Подскажите, пожалуйста, как надёжно получить путь к assembly, чтобы он работал в разных сценариях запуска?

<<>>

Использование рефлексии для получения пути к сборке

Для получения пути к сборке, из которой выполняется код, в C# используется класс Assembly из пространства имён System.Reflection. Самый надёжный способ — получить сборку, в которой находится текущий тип (например, ваш класс), а затем извлечь её местоположение. Вот как это делается:

using System;
using System.IO;
using System.Reflection;

public class TestHelper
{
    public static string GetAssemblyDirectory()
    {
        // Получаем сборку, в которой находится текущий тип
        Assembly assembly = Assembly.GetExecutingAssembly();
        
        // Получаем путь к файлу сборки (например, "C:\Projects\Tests\bin\Debug\MyTests.dll")
        string assemblyPath = assembly.Location;
        
        // Возвращаем только директорию, без имени файла
        return Path.GetDirectoryName(assemblyPath);
    }
}

// Пример использования
string path = TestHelper.GetAssemblyDirectory();
Console.WriteLine($"Путь к сборке: {path}");

Этот код гарантированно вернёт путь к папке, где находится ваш .dll или .exe файл, независимо от того, как запущено приложение — из Visual Studio, командной строки или CI-системы. Assembly.Location работает на основе метаданных CLR, поэтому он надёжен в 99% случаев.

Важные нюансы и альтернативы

  • Для .NET Core / .NET 5+: В некоторых случаях (например, при публикации как single-file) Assembly.Location может вернуть пустую строку. Тогда используйте AppContext.BaseDirectory — это свойство возвращает базовую директорию приложения, которая обычно совпадает с путём к сборке.
  • Для тестовых проектов: Если вы пишете тесты на MBUnit или NUnit, Assembly.GetExecutingAssembly() вернёт сборку с тестами. Это идеально для загрузки тестовых данных.
  • Путь к файлу, а не к папке: Если вам нужен полный путь к файлу сборки (включая имя), используйте assembly.Location напрямую, без Path.GetDirectoryName.

Пример для загрузки тестовых данных

string assemblyDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string dataFilePath = Path.Combine(assemblyDir, "TestData", "input.csv");

if (File.Exists(dataFilePath))
{
    string content = File.ReadAllText(dataFilePath);
    Console.WriteLine($"Данные загружены: {content}");
}
else
{
    Console.WriteLine($"Файл не найден: {dataFilePath}");
}

Этот подход решает вашу проблему: данные будут загружаться из папки рядом с тестовой сборкой, а не из рабочей директории.

<<>>

Использование AppContext.BaseDirectory для .NET Core / .NET 5+

Если вы работаете с современными версиями .NET (Core, 5, 6, 7 и выше), особенно после публикации приложения как single-file или в контейнерах, Assembly.Location может вернуть пустую строку или некорректный путь. В таких случаях лучшей альтернативой будет AppContext.BaseDirectory:

string basePath = AppContext.BaseDirectory;
Console.WriteLine($"Базовая директория: {basePath}");

// Для загрузки данных
string dataFile = Path.Combine(basePath, "Resources", "config.json");

AppContext.BaseDirectory всегда указывает на корневую папку приложения (где лежит основной .dll или .exe). Это свойство стабильно работает во всех сценариях, включая тесты и публикацию.

Разница между подходами:

  • Assembly.Location — точный путь к файлу конкретной сборки (может отличаться при shadow copying).
  • AppContext.BaseDirectory — базовая директория приложения, более надёжна для single-file публикации.

Для вашего случая с MBUnit я рекомендую начать с Assembly.Location, но если столкнётесь с пустыми значениями, переключитесь на AppContext.BaseDirectory.