2

I want to create generic Unit Test classes for Services. My base class is as generic as possible and I wanna pass the Service constructor as a parameter to my base class from the derived class, but I don't no how to do it in C#.

public interface IBaseServiceUnitTest<TEntity> where TEntity : BaseEntity { //...some methods } public class BaseServiceUnitTest<TEntity> : IBaseServiceUnitTest<TEntity> where TEntity : BaseEntity { private IBaseService<TEntity> _service; public BaseServiceUnitTest(Constructor ctor) { _service = ctor(); } //...implemented methods from IBaseServiceUnitTest } public class CustomEntityServiceUnitTest : BaseServiceUnitTest<CustomEntity> { public CustomEntityServiceUnitTest() : base(Constructor ctor) } 
12
  • 2
    Why do you want to pass in a constructor method and not just the IBaseService<TEntity> object? Commented Nov 27, 2019 at 23:03
  • Do you mean pass the class object? Commented Nov 27, 2019 at 23:03
  • Pretty sure you can not. Constructors are a very special function. The closest equivalent is creating instances at runtime, and thus handing in the type of class. Commented Nov 27, 2019 at 23:03
  • 3
    This might be an XY problem. It would be awesome if we could get a clearer picture of the current problem and what you are actually trying to do? Commented Nov 27, 2019 at 23:24
  • 1
    If it is known, then just pass in the service then. Commented Nov 28, 2019 at 0:41

1 Answer 1

1

I think a factory method would serve you well here.

Mark your base test fixture as abstract and define a protected abstract method with the same signature as the service constructors. Then, call that method in your base fixture's setup logic.

You will have to implement the abstract method for each derived test class, but I think it's a reasonable compromise.

Note that I also removed the interface from the test class. Based on the sample code you provided, it's entirely redundant with the now-abstract base class. Of course, it might be useful for some reason not apparent from your example--if so, you can keep it.

public class BaseServiceUnitTest<TEntity> where TEntity : BaseEntity { private IBaseService<TEntity> _service; public BaseServiceUnitTest(Constructor ctor) { _service = Create(/* your mocked dependencies here */); } protected abstract IBaseServce<TEntity> Create(Dependency1 d1, Dependency2 d2); //...implemented methods from IBaseServiceUnitTest } public class CustomEntityServiceUnitTest : BaseServiceUnitTest<CustomEntity> { // "arg1, arg2" protected override IBaseService<CustomEntity> Create(Dependency1 d1, Dependency2 d2) => new BaseService<CustomerEntity>(d1, d2); } 

Addendum

If you really want to make things automagic, you could try the answer to this question. It'll work, but you'll sacrifice "F12-ability" (the ability to find and navigate through references using Visual Studio's shortcuts) and compile-time verification of your constructors and their arguments. Personally, I'd probably use the factory method.


Addendum #2

For completeness, it's also worth noting that if your service-under-test had no constructor arguments, you might also be able to use the new constraint. Based on your comments, it doesn't sound like it will work in this case, but it might be useful another time.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.