developerabab
developerabab

Reputation: 41

How to mock an array during unit test which is injected in Dotnet Core

I have a class that has a dependency on two other classes that implements the same interface. So in Startup.cs

services.AddTransient<ICommonInterface, Class1>();
services.AddTransient<ICommonInterface, Class2>();

Now, on a method in the class that depends on Class1 and Class2, I have the code as,

public class Class3
{
   private readonly IEnumerable<ICommonInterface> _dependentClasses;

   class3(IEnumerable<ICommonInterface> dependentClasses){
     _dependentClasses = dependentClasses; // injected
   }
   public MethodAny(SomeArgument){
     var result1 = _dependentClasses[0].SomeCommonMethodInTheInterface(SomeArgument);
     var result2 = _dependentClasses[1].SomeCommonMethodInTheInterface(SomeArgument);
      //and so on
   }
}

In the unit test I want to do something like the below pseudocode

public Class3Specs(){
 private readonly IEnumerable<ICommonInterface>();     
 private readonly Class3 _class3;

 Class3Specs(){
  _dependentClasses = Substitute.For<IEnumerable<ICommonInterface>();
  _class3 = new Class3(_dependentClasses);
 }
 _dependentClasses.ToList()[0].SomeCommonMethodInTheInterface.Returns(new Return Type of that method);
}

Any inputs will be highly helpful.Thanks in advance.

Upvotes: 1

Views: 750

Answers (1)

Enrico Massone
Enrico Massone

Reputation: 7348

Usually for the unit testing I use the following libraries:

  • NUnit as the test framework
  • Moq as the mocking library
  • Autofixture if I need help in creating objects with many properties in the test setup

The following example is based on this set of libraries, but you can easily adapt what follows for your preferred set of libraries.

The interface:

public interface IMessageGenerator 
{
  string GetMessage();
}

Two implementations of the interface (you don't actually need these classes for the unit tests, I report them just for the sake of completeness):

public sealed class FooMessageGenerator: IMessageGenerator 
{
  public string GetMessage() => "Foo";
}

public sealed class BarMessageGenerator: IMessageGenerator 
{
  public string GetMessage() => "Bar";
}

The class you want to test:

public sealed class SomeService 
{
  private readonly IMessageGenerator[] _messageGenerators;

  public SomeService(IEnumerable<IMessageGenerator> messageGenerators)
  {
     if (messageGenerators is null) 
     {
       throw new ArgumentNullException(nameof(messageGenerators));
     }

    _messageGenerators = messageGenerators.ToArray();
  }
  
  public string SaySomething() 
  {
    var statement = string.Join(
      " ", 
      _messageGenerators.Select(x => x.GetMessage())
    );
    return statement;
  }
}

The test class:

[TestFixture]
public sealed class SomeServiceTests 
{
  [Test]
  public void SaySomething_Joins_Messages_Generated_By_Message_Generators() 
  {
    // ARRANGE
    var fakeGenerator1 = new Mock<IMessageGenerator>();
    var fakeGenerator2 = new Mock<IMessageGenerator>();

    fakeGenerator1
      .Setup(m => m.GetMessage())
      .Returns("Hello");

    fakeGenerator2
      .Setup(m => m.GetMessage())
      .Returns("World");

    var target = new SomeService(new List<IMessageGenerator>() { fakeGenerator1, fakeGenerator2 });

    // ACT
    var result = target.SaySomething();

    // ASSERT
    Assert.AreEqual("Hello World", result);
  }
}

Upvotes: 2

Related Questions