2012-03-02 2 views
0

я следующий кодМодульное тестирование Взаимодействие методов в одном классе в C#

public ClassToTest : IClassToTest 
{ 
    private readonly DBRepository rep; 

    public bool MethodA() 
    { 
     //Some logic 
     var result=MethodB(); 
     //Do some logic against result; 
    } 
    public ResultType MethodB() 
    { 
     return Rep.GetResult(); 
    } 
} 

Если я хочу модульного тестирования Methoda, что лучшая практика, чтобы проверить взаимодействие между Methoda и MethodB? Я имею в виду, чтобы проверить Methoda как тестирование MethodB насмехаясь над зависимостью базы данных Rep, так же, как Methoda имеет следующую реализацию

public bool MethodA() 
    { 
     //Some logic 
     var result=Rep.GetResult(); 
     //Do some logic against result; 
    } 

Но это не интуитивно, проверяя логику в коде и метод испытания. Я ищу решение, подобное описанному здесь для Java.

unit testing composite service methods

Но это не работает на C#.

Один дополнительный вопрос, что, если MethodB является конфиденциальным, не имеет значения для стратегии тестирования устройства?

Обновление: предпочитают не изменять структуру класса. например, не сделать MethodB виртуальным или переместить методB из класса в другой тест

Заранее спасибо.

ответ

2

Вы не хотите, чтобы проверить взаимодействие между MethodA и MethodB, вы хотите проверить, что MethodA возвращает ожидаемый bool результат, учитывая определенный контекст.

Тот факт, что MethodA вызывает MethodB, не является германом для этого теста; но тот факт, что в какой-то момент будет называться Rep.GetResult().

Как уже упоминалось, вы можете издеваться зависимость Rep, так что это не имеет значения, является ли MethodB является public или private.

  1. Мок и ввести зависимость
  2. вызова MethodA
  3. Утверждай против результата
+0

Спасибо, Джей. Думаю, это ответ. Я просто беспокоюсь о том, что метод тестирования не соответствует логике ** MethodA **. которые могут иметь меньшую удобочитаемость, если метод тестирования имеет сложную логику. – Zhao

+0

@zhaow Можете ли вы объяснить, что вы имеете в виду, когда говорите, что метод тестирования не соответствует логике MethodA? – Jay

+0

Итак, вызывающая иерархия - MethodA => MethodB => Rep.GetResult(), при модульном тестировании для MethodB я уже тестировал MethodB => Rep.GetResult(). Затем, когда я тестирую MethodA, я чувствую, что более ясный и интуитивный тест MethodA => MethodB. Но если логика MethodB и MethodA не сложна, то проверяется MethodA => Rep.GetResult(). – Zhao

0

Вы хотите изолировать свои методы, которые вы тестируете, то есть хотите высмеять MethodB во время тестирования MethodA и наоборот.

Кроме того, существует парадигма тестирования для проверки контракта (или интерфейса) классов. В этой парадигме вы не будете беспокоиться о непубличных не виртуальных методах. Я как бы издеваюсь над тем, что могу.

Я рекомендую вам использовать насмешливый фреймворк (самодовольный, носорог, moq, easymock). Smug - самый крутой, но он еще не завершен. Я просто покажу вам код ниже (так оно будет работать без насмешливые рамки, которые помогут вам).

public enum ResultType 
{ 
    Ok, 
    NotOk, 
} 

public abstract class DBRepository 
{ 
    public abstract ResultType GetResult(); 
} 

public class ClassToTest 
{ 
    public DBRepository Rep { get; set; } 

    public virtual bool MethodA() 
    { 
    //Some logic 
    var result = MethodB(); 
    //Do some logic against result; 

    return result == ResultType.Ok; 
    } 

    protected virtual ResultType MethodB() 
    { 
    return Rep.GetResult(); 
    } 
} 

public class DBRepositoryMock : DBRepository 
{ 
    public ResultType FakeReturn { get; set; } 
    public override ResultType GetResult() 
    { 
    return FakeReturn; 
    } 
} 

public class ClassToTest_MethodA : ClassToTest 
{ 
    public ResultType MethodB_FakeReturn { get; set; } 

    protected override ResultType MethodB() 
    { 
    return MethodB_FakeReturn; 
    } 
} 

// tests 

[TestMethod] 
public void Test1() 
{ 
    ClassToTest mock = new ClassToTest_MethodA(); 
    (mock as ClassToTest_MethodA).MethodB_FakeReturn = ResultType.Ok; 
    Assert.IsTrue(mock.MethodA()); 
} 

// or using injection 
[TestMethod] 
public static void Test2() 
{ 
    var obj = new ClassToTest(); 
    obj.Rep = new DBRepositoryMock { FakeReturn = ResultType.NotOk }; 
    Assert.IsFalse(obj.MethodA()); 
} 
+0

Спасибо за быстрый и подробный ответ. Я просто обновил свой вопрос, я предпочитаю не менять существующую структуру класса. Я чувствую, что нет необходимости делать метод виртуальным для целей тестирования. – Zhao

+1

:(Вы выбрали другой ответ, вы увидите, что мой ответ на самом деле предоставляет 2 решения, а не только одно. Моим вторым решением является введение значения DBRepository, первое из которых было для тех, кто считает, что им нужно протестировать каждый метод индивидуально. – payo

+0

Извините, я очень признателен за ваш ответ, и это хороший ответ и дает два правильных решения. Но ответ Джей ясно дает понять, что я должен делать в лучшем случае при модульном тестировании. Хотя вы предоставили два решения, но в то время мне было непонятно, что это проблема предпочтений. Вот почему я выбираю ответ Джей. Еще раз спасибо за вашу помощь. :) – Zhao

0
[TestMethod] 
public void MethodAReturnsTrueGivenSomeDataAndCondition() 
{ 
IDBRepository mockRepo = new Mock<IDBRepository>(); //Create a mock of your repository call 
ClassToTest subjectToTest = new ClassToTest(mockRepo.Object); //Inject the dependency 

mockRepo.SetUp(r=>r.GetResult()).Returns(someSampleTestData); //You're setting up the object that might return you true to return when mock repo will be called, by default it returns the default or null usually 

var result = subjectToTest.MethodA(); 
mockRepo.Verify(r=>r.GetResult(), Times.Once); //Make sure your repo method was called 
Assert.IsTrue(result); 

} 

Что-то вроде этого, используя Moq в качестве основы выборки насмешливый.

+0

Благодарим вас за ответ. Я могу просто скопировать его. :) – Zhao

Смежные вопросы