This is a migrated thread and some comments may be shown as answers.

Testing implementation of abstract class

3 Answers 545 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
Stefano
Top achievements
Rank 1
Stefano asked on 05 Jun 2019, 03:58 PM

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

 

3 Answers, 1 is accepted

Sort by
0
Mihail
Telerik team
answered on 06 Jun 2019, 08:59 AM
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
0
Stefano
Top achievements
Rank 1
answered on 06 Jun 2019, 10:12 AM

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

0
Mihail
Telerik team
answered on 10 Jun 2019, 11:34 AM
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
Tags
General Discussions
Asked by
Stefano
Top achievements
Rank 1
Answers by
Mihail
Telerik team
Stefano
Top achievements
Rank 1
Share this question
or