How to unit test a method with hardcoded parameters?

I have a class with a method. What this method check an assembly/namespace and read all classes with the name ProductModel in that namespace:

    public static IEnumerable<ProductModel?> GetProductModels()
    {
        var typesList = Assembly.GetExecutingAssembly()
            .GetTypes().Where(x =>
                x.Name.Contains("ProductModel") && // This is the name of the classes
                x.FullName!.Contains("MyProject.Domain.ProductTypes")) // This is the namespace of the project
            .ToList();

        var ProductModelLists = typesList.Select(x =>
       {
           return GetProductModelMethod(x);
       });

        if (ProductModelLists == null)
        {
            throw new ArgumentException("No ProductModel Found");
        }
        else{
          return ProductModelLists;
        }   
    }

This class and method is in the same project and name space as the ProductTypes/ProductModels – MyProject.Domain.ProductTypes.

I want to use XUnit to test 2 scenarios – one where there are ProductModels and one where there are none and the Argument exception is thrown.

Since the values are hardcoded inside the method, it looks almost impossible to me. Does anyone have any hint of how to do something similar?

Answer

Tight coupling to implementation details make isolating that code difficult. Consider refactoring to use abstractions along with explicit dependency principle to make the code more SOLID.

Given that the subject member under test is a static function, I assume this is within some static utility class. The core functionality could still be refactored into it’s own function that allows for inputs that can be manipulated.

public static IEnumerable<ProductModel?> GetProductModelsCore(IEnumerable<Type> types) {
    var typesList = types.Where(x =>
            x.Name.Contains("ProductModel") && // This is the name of the classes
            x.FullName!.Contains("MyProject.Domain.ProductTypes")) // This is the namespace of the project
        .ToList();

    var ProductModelLists = typesList.Select(x => {
       return GetProductModelMethod(x);
    });

    if (ProductModelLists == null) {
        throw new ArgumentException("No ProductModel Found");
    } else {
      return ProductModelLists;
    }   
}

And called from the main function

public static IEnumerable<ProductModel?> GetProductModels() =>
    GetProductModelsCore(Assembly.GetExecutingAssembly().GetTypes());

The core functionality can be tested in isolation with fake types that satisfy the desired scenarios.

Again, ideally this should be moved to services with abstractions that allow for a more SOLID code base that lends itself to better maintenance, but based on the original code provided that is currently outside of the scope of this answer.