Approach on mocking ServiceStack service being called by another ServiceStack service

StackOverflow https://stackoverflow.com/questions/23296415

  •  09-07-2023
  •  | 
  •  

سؤال

Let's say we have a situation where a service would call other services in ServiceStack.

From reading around, this is how one would call another service:

public class CompanyService : Service
{
    public SetupCompanyResponse Any(SetupCompany request)
    {
        var employeeService = base.ResolveService<EmployeeService>();

        // Do something with employeeService
        var response = employeeService.Any(new SetupEmployees());

        return new SetupCompanyResponse { NumOfEmployeesCreated = response.Count };
    }
}

Question: How do I mock EmployeeService if I'm unit-testing CompanyService?

Easiest way I could think of is to generate an IEmployeeService interface so that it's easily mockable. However I'm not sure if base.ResolveService<T> will be able to properly resolve and auto-wire a ServiceStack service, given its interface instead, like so:

var employeeService = base.ResolveService<IEmployeeService>();

Especially when we are registering services this way (which I assume is configuring the object resolution based on concrete class, and not the interface e.g IEmployeeService)

public HelloAppHost() : base("Hello Web Services", typeof(HelloService).Assembly) { }

Update:

Apparently I'm able to somewhat achieve this simply by:

1) Registering the service interface with its implementation

public static void SetupServices(Container container)
{
    container.RegisterAs<EmployeeService, IEmployeeService>();
}

2) Using the same exact code to resolve, except now I pass in the interface. The service is successfully resolved.

var employeeService = base.ResolveService<IEmployeeService>();

3) All I need to do now is to override the resolver, and the service dependency should be totally mockable.

Question: Is this also a valid approach? Why or why not?

هل كانت مفيدة؟

المحلول

ServiceStack's Service class resolves all its dependencies from an IResolver, defined by:

public interface IResolver
{
    T TryResolve<T>();
}

This can be injected in ServiceStack's Service class in an number of ways as seen by the implementation:

public class Service : IService, IServiceBase, IDisposable
{
    public static IResolver GlobalResolver { get; set; }

    private IResolver resolver;
    public virtual IResolver GetResolver()
    {
        return resolver ?? GlobalResolver;
    }

    public virtual Service SetResolver(IResolver resolver)
    {
        this.resolver = resolver;
        return this;
    }

    public virtual T TryResolve<T>()
    {
        return this.GetResolver() == null
            ? default(T)
            : this.GetResolver().TryResolve<T>();
    }
    ...
}

Which you can use to control how Services resolve dependencies.

An easy way to unit test Services is to use a BasicAppHost as seen on the Testing wiki, i.e:

appHost = new BasicAppHost().Init();
var container = appHost.Container;

container.Register<IDbConnectionFactory>(
    new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider));

container.RegisterAutoWired<CompanyService>();
container.RegisterAutoWiredAs<StubEmployeeService, EmployeeService>();

Where StubEmployeeService is your stub implementation of EmployeeService, e.g:

public class StubEmployeeService : EmployeeService 
{
    public SetupEmployeesResponse Any(SetupEmployees request)
    {
        return new SetupEmployeesResponse  { ... };
    }
}

You can also register Services using any of the registration methods ServiceStack's IOC Supports if you prefer to use your own mocking library.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top