2013-11-14 5 views
4

Я работаю с библиотекой FakeItEasy, чтобы создавать подделки для моих модульных тестов.Как подделать действие <> с FakeItEasy

У меня есть ClassUnderTest, на котором я хочу протестировать метод MethodToTest(Data dataObject). Этот метод вызова метода интерфейса, который я хочу подделать:

public interface IFoo 
{ 
    void Execute(Action<IDataAccess> action); 
} 

public class ClassUnderTest 
{ 
    private IFoo _foo; 

    public ClassUnderTest(IFoo foo) 
    { 
    _foo = foo; 
    } 

    public void MethodToTest(Data dataObject) 
    { 
    _foo.Execute(dataAccess => dataAccess.Update(dataObject)); 
    } 
} 

public interface IDataAccess 
{ 
    void Update(Data data); 
} 

public class Data 
{ 
    public int Property { get; set; } 
} 

В моих модульных тестов я хочу проверить, если метод испытаний требует интерфейс правильно (с правильным значением свойства):

[TestClass] 
public class UnitTest1 
{ 
    [TestMethod] 
    public void TestMethod1() 
    { 
    var foo = A.Fake<IFoo>(x => x.Strict()); 
    A.CallTo(() => foo.Execute(dataAccess => dataAccess.Update(A<Data>.That.Matches(d => d.Property == 20))));  

    var cut = new ClassUnderTest(foo); 

    cut.MethodToTest(new Data { Property = 20 });  
    } 
} 

Но в этом тесте что-то не так. Я получаю исключение:

Метод испытания TestProject1.UnitTest1.TestMethod1 бросил исключение: FakeItEasy.ExpectationException: Вызов к не настроен метод «Execute» строгой подделки.

Есть ли у кого-нибудь представление о том, как мне нужно правильно настроить оператор CallTo()?

Заранее благодарен!

+0

Легко, я бы сказал ...? :) (хорошо, хорошо, я дам это прочитать ...) – Noctis

+0

Вы уверены, что код, который вы представили, даже компилируется? 'ClassUnderTest' не имеет конструктора без параметров (я предполагаю, что это класс, но это также отсутствует в коде), но вы, кажется, используете один ... – decPL

+0

@ decPL: вы правы, я исправил образец выше , foo-fake передается в costructor. – rhe1980

ответ

4

Обновленный пример действительно помогает, @ rhe1980.

Сначала несколько замечаний по поводу теста вы предоставили:

  1. метод A.CallTo ничего не делать - это не настройка поведения (с .Invokes или .Returns или даже .DoesNothing) или проверки, что метод (например, с .MustHaveHappened).
  2. Сравнение Action s выглядит грубо. Я нашел совет по адресу Compare Delegates Action<T>, но если бы это был я, я бы взял немного другую липкость.

Вместо того чтобы попытаться сравнить Action делегатом эталонной модели, я полагал, что я мог бы эмулировать захватывая действие, подаваемое Execute, а затем запустить его на IDataAccess и посмотреть , что действие делает. К счастью, у нас есть FakeItEasy, чтобы помочь с этим!

Я имел успех с этим испытанием:

[TestMethod] 
public void TestMethod1() 
{ 
    // Arrange 
    var foo = A.Fake<IFoo>(x => x.Strict()); 

    var fakeDataAccess = A.Fake<IDataAccess>(); 

    A.CallTo(() => foo.Execute(A<Action<IDataAccess>>.Ignored)) 
        .Invokes((Action<IDataAccess> action)=>action(fakeDataAccess)); 

    var cut = new ClassUnderTest(foo); 

    // Act 
    cut.MethodToTest(new Data { Property = 20 }); 

    // Assert 
    A.CallTo(() => fakeDataAccess.Update(A<Data>.That.Matches(d => d.Property == 20))) 
     .MustHaveHappened(); 
} 

Я надеюсь, что это помогает.

+0

Отлично! именно то, что мне нужно. Спасибо! – rhe1980

1

Если я правильно понял ваши намерения, вам нужно использовать что-то следующим образом:

A.CallTo(() => foo.Execute(A<Action<IDataAccess>>.Ignored).MustHaveHappened(); 
+0

Согласен, и в идеале после запуска 'MethodToTest'. Я думаю, что есть и другие проблемы с образцом кода. См. Мой комментарий к вопросу. –