Как передать макет интерфейсного объекта в основной класс c # - PullRequest
0 голосов
/ 26 июня 2018

У меня есть следующий код:

    public interface Iinterface
    {
        Task<bool> RetrieveFromDataBase();
    }
    public class Class1 : Iinterface
    {
        public async Task<bool> RetrieveFromDataBase()
        {
            //do something
            return true;
        }
    }
    public class AnotherClass
    {
        Class1 c = new Class1();       
        public AnotherClass(Class1 obj)
        {
           c = obj;
        }
        public async Task<bool> ExecuteData()
        {
            var result = await c.RetrieveFromDataBase();
            if (result)
            {
                //do some calculation
            }
            return true;
        }
    }

Теперь я пытаюсь написать контрольные примеры для метода ExecuteData.В этом методе мне нужно обойти RetrieveFromDataBase метод.Поэтому я пытаюсь это высмеять.Ниже приведен код, который я написал.

    [TestClass()]
    public class AnotherClassTests
    {
        [TestMethod()]
        public async Task ExecuteDataTest()
        {
            Task<bool> retValue = RetrieveFromDataBaseMoq(); // this returns true 
            var moq = new Mock<Iinterface>();
            moq.Setup(x => x.RetrieveFromDataBase()).Returns(retValue);

            AnotherClass obj = new AnotherClass((Class1)moq.Object); // error thrown from here
            var result = await obj.ExecuteData();
            Assert.IsTrue(result);
        }
    }

Выполненное моделирование выполнено успешно, т. Е. Не выдает никакой ошибки.Проблема, с которой я здесь сталкиваюсь, заключается в том, что, когда я передаю этот макет объекта в конструктор, возникает ошибка System.InvalidCastException: невозможно преобразовать объект "Castle.Proxies.Iinterface" в тип "Class1".

Я знаю, что он не может конвертировать макет интерфейса в конкретный тип класса.Но есть ли способ исправить эту ошибку или передать макет объекта в основной класс в любом случае.

Большое спасибо!

1 Ответ

0 голосов
/ 26 июня 2018

вы должны объявить переменную c как Iinterface.Это одно из преимуществ использования интерфейсов.Вы должны зависеть от контракта (интерфейса), а не от конкретных реализаций.После этого вы не связаны с конкретными классами.

 public class AnotherClass
{
    Iinterface c; //I removed the default new since it will get assigned in constructor     

    public AnotherClass(Iinterface obj)
    {
       c = obj;
    }

    public async Task<bool> ExecuteData()
    {
        var result = await c.RetrieveFromDataBase();
        if (result)
        {
            //do some calculation
        }
        return true;
    }
}

Проблема, с которой я здесь сталкиваюсь, заключается в том, что класс Class1 также имеет некоторые другие методы и переменные, которые не объявлены в интерфейсе.

Вы можете создать композицию внутри Class1 и переместить TInterface как зависимость внутри Class1.Имейте в виду, что интерфейс - это то, что вы будете высмеивать в модульном тесте

public class Class1 
{ 
    public TIinterface tinterface{get;private set;}
    public Class1(TIinterface interface)
    {
        tinterface= interface;
    }
}
public class YourCustomImplementation:TIinterface 
{
   public async Task<bool> RetrieveFromDataBase()
   {
        //do something
        return true;
   }
}



public class AnotherClass
{
    Class1 c = new Class1();       
    public AnotherClass(Class1 obj)
    {
       c = obj;
    }
    public async Task<bool> ExecuteData()
    {
        var result = await c.tinterface.RetrieveFromDataBase();
        if (result)
        {
            //do some calculation
        }
        return true;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...