简体   繁体   中英

rhino mock an interface IA which implements interface IB with abstract class aB

I have a situation where I have in interface

public interface IA : IB
{
}

where

public interface IB
{
    List<string> Errors{get;}
    void AddError(string error);
}

with an abstract class

public abstract class B
{
    private List<string> errors = new List<string>();
    public List<string> Errors{get{return errors;}}
    public void AddError(string error)
    {
        if (!errors.Contains(error)) 
            errors.Add(error);
    }        
}

And I have a method on another class like:

public class MyClass
{
    public void MyMethod(IA obj)
    {            
        obj.AddError("some string");
    }
}

then I have a unit test where I would like to test that MyClass does what it is supposed to by passing in a stubbed IA:

public void Test()
{
    var sut = new MyClass();
    var input = MockRepository.GenerateStub<IA>();
    sut.MyMethod(input);
    Assert.AreEqual(1, input.Errors.Count);
}

but when it comes to the assertion, Errors is null as the base class B is not included in the stub for IA, is there any way to specify that I want the implementation of IB to be provided by an abtsract class without having to create a concrete class that derives from B?

I have missed some of the detail from this, but I will expand by saying that there are a set of interfaces like IA all implementing IB, and a set of classes like MyClass each taking a different interface and the detail of MyMethod depends on the interface IA that it accepts, but the interfaction with the implementation of IB is always the same.

One possible solution is to create an abstract implementation of IA

public abstract class A : B, IA
{
    //abstract implementations of all properties and methods on IA, nothing concrete
}

this can then be stubbed in the unit test:

public void Test()
{
    var sut = new MyClass();
    var input = MockRepository.GenerateStub<A>();
    sut.MyMethod(input);
    Assert.AreEqual(1, input.Errors.Count);
}

and the propertis and methods on A that need to be stubbed (or mocked) can than be done.

It does mean that an additional class nedds to be wiritten fr each interface that exists in the vein of IA, whic is far from ideal, but its the nly way I see around this for now.

Interface stands for behavioral contract. It is by its nature not coupled with any implementation. What you want is a mock-ed object who carries behavior defined by class B (in other words you need a mocked B object), and at the same time implements IA.

You could use multi, partial mock to achieve it:

var sut = new MyClass();
var input = MockRepository.GeneratePartialMock<B, IA>();
sut.MyMethod((IA)input);
Assert.AreEqual(1, input.Errors.Count);

GeneratePartialMock is the method to mock a class who already has some behavior defined. Basically it gives you the capability to rewrite(stub) override-able methods defined in a class. And if you don't stub a method, the original behavior will be invoked.

You can include more interfaces (in your case, IA) in the type parameter list to dynamically add behavior to your mock-ed object.

Note you have to revise the code you posted in order to make it work:

  1. Initialize () should be defined in the interface IB
  2. Methods should be defined as virtual in class B

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM