Testing implementation of abstract class

4 posts, 0 answers
  1. Stefano
    Stefano avatar
    4 posts
    Member since:
    Feb 2019

    Posted 05 Jun 2019 Link to this post

    Hi,

     

    I'd like to test the implementation of the my abstract class, but I'm not able to intercept the constructor of the base class.

    Here the snippet code:

     

    public abstract class Base
    {
        public virtual void Start(IContext context)
        {
             \\ do something
        }
    }
    public class Child : Base
    {
        public override void Start(IContext context)
        {
             \\ do something
        }
    }

     

    I'd like to test it like this:

    private Base mBase;
    private Child mPlugin;
     
    [TestInitialize]
    public void Initialize()
    {
       mBase = Mock.Create<Base>(Constructor.Mocked);
       mPlugin = new Child();
    }
     
    [TestMethod]
    public void TestStart()
    {
        IContext mockContext = Mock.Create<IContext>();
        Mock.Arrange(() => mBase.Start(mockContext)).DoNothing();
         
        // test plugin code
         
        mPlugin.Start(mockContext);
    }

     

    What is wrong?

     

    Thanks,

    Ste

     

  2. Mihail
    Admin
    Mihail avatar
    263 posts

    Posted 06 Jun 2019 Link to this post

    Hi Stefano,

    If I understand correctly your scenario you missed to add the IgnoreInstance method in the arrange. Here is your code with some modifications to better represent the result:
    public abstract class Base
    {
        public virtual int Start(IContext context)
        {
            return 0;
        }
    }
    public class Child : Base
    {
        public override int Start(IContext context)
        {
            var value = base.Start(context);
     
            value += 10;
     
            return value;
        }
    }

    And here is how the test should look like:
    [TestMethod]
    public void TestMethod()
    {
        // Arrange
        var mBase = Mock.Create<Base>(Constructor.Mocked);
     
        IContext mockContext = Mock.Create<IContext>();
        Mock.Arrange(() => mBase.Start(mockContext)).IgnoreInstance().Returns(5);
     
        // Act
        var child = new Child();
        var result = child.Start(mockContext);
     
        // Assert
        Assert.AreEqual(15, result);
    }

    If this is not what you are looking for, please provide more detailed information on your scenario.




    Regards,
    Mihail
    Progress Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  3. Stefano
    Stefano avatar
    4 posts
    Member since:
    Feb 2019

    Posted 06 Jun 2019 in reply to Mihail Link to this post

    Hi Mihail,

     

    Thanks for the replay. I'm trying to test the base and the child class independently.

    In your example,I'm not able to intercept the execution of the base constructor. 

    For example, if you have this code:

    public abstract class Base
    {
        protected Base(string name)
        {
            // other operation that I don't want test in the child test
        }
     
        public virtual int Start(IContext context)
        {
            return 0;
        }
    }
    public class Child : Base
    {
        public Child(string name) : base(name)
        {
        }
     
        public override int Start(IContext context)
        {
            var value = base.Start(context);
      
            value += 10;
      
            return value;
        }
    }

     

     

    Using your test code, I saw that the constructor of the base class is called.

     

    Thank again,

    Stefano

  4. Mihail
    Admin
    Mihail avatar
    263 posts

    Posted 10 Jun 2019 Link to this post

    Hello Stefano,

    You could mock the constructor of an abstract class by creating an expression about the constructor call and arrange that expression. Here is how I have modified the base class in order to test it:
    public abstract class Base
    {
        public string Name { get; }
        public Base(string name)
        {
            this.Name = name + " text";
        }
     
        public virtual int Start(IContext context)
        {
            if (String.IsNullOrEmpty(this.Name))
            {
                return 0;
            }
            else
            {
                return 10;
            }
        }
    }
    public class Child : Base
    {
        public Child(string name) : base(name)
        {
     
        }
     
        public override int Start(IContext context)
        {
            var value = base.Start(context);
     
            value += 10;
     
            return value;
        }
    }

    And here is how the test looks like:
     [TestMethod]
     public void TestMethod_AbstractConstructor()
     {
         // Arrange
         string argValue = "John Doe";
         var lambda = GetTypeConstructor<Base>(Expression.Constant(argValue));
     
         Mock.Arrange(lambda).DoNothing().Occurs(1);
     
         IContext mockContext = Mock.Create<IContext>();
     
         // Act
         var child = new Child(argValue);
         var result = child.Start(mockContext);
     
         // Assert
         Assert.AreEqual(10, result);
     }
     
     private static Expression<Func<T>> GetTypeConstructor<T>(params Expression[] arguments)
     {
         Type targetType = typeof(T);
         List<Type> paramTypes = new List<Type>();
         foreach (Expression argument in arguments)
         {
             paramTypes.Add(argument.Type);
         }
         ConstructorInfo constructorInfo =
             targetType.GetConstructor(BindingFlags.Instance | BindingFlags.Public, null,
                 CallingConventions.HasThis, paramTypes.ToArray(), null);
     
         return Expression.Lambda<Func<T>>(Expression.New(constructorInfo, arguments));
     }

    I understand that it is a bit complex approach. This is why we will consider implementing an easier way of mocking an abstract constructor in some of our future releases.

    Regards,
    Mihail
    Progress Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
Back to Top