2013-07-29 6 views
5

으로 사용합니다. FakeItEasy를 사용하여 객체의 메서드가이 동일한 객체에서 다른 메서드를 호출하는지 확인하려면 어떻게합니까?FakeItEasy의 A.CallTo()를 동일한 객체의 다른 메소드

테스트 :

[TestMethod] 
public void EatBanana_CallsWillEat() 
{ 
    var banana = new Banana(); 
    var myMonkey = new Monkey(); 

    myMonkey.EatBanana(banana); 

    //this throws an ArgumentException, because myMonkey is a real instance, not a fake 
    A.CallTo(() => myMonkey.WillEat(banana) 
    .MustHaveHappened(); 
} 

더 클래스 :

public class MyMonkey { 
    private readonly IMonkeyRepo _monkeyRepo; 

    public MyMonkey(IMonkeyRepo monkeyRepo) { 
    _monkeyRepo = monkeyRepo; 
    } 

    public void EatBanana(Banana banana) { 
    //make sure the monkey will eat the banana 
    if (!this.WillEat(banana)) { 
     return; 
    } 

    //do things here 
    } 

    public bool WillEat(Banana banana) { 
    return !banana.IsRotten; 
    } 
} 

내가 제안을 개방적이야. 이 모든 잘못을 저 지르게되면 알려주세요.

+2

내가 이해할 때, 이것은 FIE가 무엇을위한 것이 아닌가. FIE는 가짜 오브젝트를 제공하여 프로덕션 코드를 더 쉽게 찌를 수 있습니다. 당신이 지적한 것처럼, 당신은 가짜가 아닙니다. 제 경험상, 이런 종류의 테스트는 일반적으로 좋은 생각이 아닙니다. MyMonkey 클래스는 자체 완비 된 단위 여야하며 자체 메서드 호출 여부를 염려하지 않고 바나나를 먹도록 명령받은 경우 전반적인 동작을 테스트하는 것이 좋습니다. 예를 들어, 바나나가 "// 여기에있는 일들"에서 일어나는 일에서 단서를 기반으로 먹었는지 여부를 말할 수 있습니까? –

+0

@BlairConrad 내 실제 시나리오에서, WillEat은 더 복잡하고 고유 한 테스트를 가지고 있으며 이것은 EatBanana의 테스트 중 하나 일뿐입니다. 이 테스트에서 EatBanana가 실제 WillEat을 호출하게한다면 한 가지 테스트에서 두 가지 기능을 테스트하지 않겠습니까? WillEat이 바뀌면 테스트가 중단 될 수 있습니다. 그게 나쁜 소식입니다. 맞습니까? –

+4

당신의 요점을 봅니다. 까다 롭습니다. WillEat이 다른 객체에 살면, 우리는 그 객체의 위조를 촉구하고 그것을'MyMonkey'에 주입합니다 (고통 스럽습니다). 내가 말할 수있는 것은 클라이언트의 관찰 가능한 결과에 의존하여 외부에서 'MyMonkey'를 테스트하는 것이 가장 좋은 기본 위치라고 생각합니다. 하지만 생각을 해봤지만 고통을 덜어 줄 수있는 솔루션을 발견하고 테스트 횟수를 줄일 수있을뿐만 아니라 주어진 횟수만큼 중단 될 수 있습니다. 당신은 코드가 가장 잘 알고 있으므로, 그것이 당신을 위해 작동한다면 ... 나는 단지 당신이 대안을 알고 있기를 바랬다. –

답변

2

이렇게 할 수 있습니다. WillEat 메서드가 가상 인 경우 - 그렇지 않으면 FakeItEasy가 가짜로 만들 수 없습니다. 그 변화와

, 당신이 할 수 있습니다 :

[TestMethod] 
public void EatBanana_CallsWillEat() 
{ 
    var fakeMonkey = A.Fake<MyMonkey>(); 

    fakeMonkey.EatBanana(new Banana()); 

    A.CallTo(()=>fakeMonkey.WillEat(A<Banana>._)).MustHaveHappened(); 
} 

나는 아직도 (나는 의견으로 담보로) 좋은 생각입니다 확신 아니에요 - 난 당신이 다른에 의존 더 나을 거라고 생각 관찰 가능한 행동이지만, 나는 당신의 시스템에 익숙하지 않다. 이것이 최선의 방법이라고 생각한다면 예제 코드가 도움이 될 것입니다.

3

테스트 대상을 왜 조롱 했습니까? 정확히을 테스트하려고합니까? WillEat로 전화 한 경우 확인이 거의 가치가 없음을 의미합니다. 소비자에게 어떤 정보를 제공합니까? 어쨌든 소비자는 방법이 어떻게 실행되는지 상관하지 않는다. 소비자는 무엇이 인지 관심이있어서입니다.

원숭이가 바나나를 먹을 때 어떤 일이 발생합니까? 은 부패하지 않습니다.? 제대로 위조 여기 주입 IMonkeyRepo에 검증 모든 종류를 만들 수 있습니다

[TestMethod] 
public void EatBanana_CAUSES_WHAT_WhenBananaIsNotRotten() 
{ 
    var repo = A.Fake<IMonkeyRepo>(); 
    var monkey = new Monkey(repo); 
    var freshBanana = new Banana { IsRotten = false }; 

    monkey.EatBanana(freshBanana); 

    // verifications here depend on what you expect from 
    // monkey eating fresh banana 
} 

참고 : 귀하의 시험은이 질문에 대답해야한다.

+0

좋은 지적. WillEat을 조롱하지 않고 EatBanana가 실제 WillEat을 호출하도록 허용한다면 한 테스트에서 두 가지 기능을 테스트 할 수 있습니까?위의 예제에서 WillEat은 사소한 일이지만 실제 상황에서는 더 복잡하고 인수를 기반으로 파생 된 객체를 반환하므로 조롱을당한 후이를 확인하는 것이 올바른 방법 일 것입니다. 필자는 현재 WillEat에 대한 별도의 테스트와 EoBanana에 대한 몇 가지 다른 테스트를 수행했습니다. 여기에는 repo가 ​​호출되었는지 확인하는 작업이 포함됩니다. 어쩌면 내가 너무 세분화되어있을거야? –

+3

@ JoshNoe : 또는 충분히 세분화되지 않았습니다. 'WillEat'이 그 복합체라면, 어쩌면 그것 자체의 수업에서 살아야할까요? 어쩌면이 기능을 * food-evaluator-sort-of-thing *에 추출하여 원숭이에게 주입하는 것이 더 합리적일까요? 테스트는 * 간단해야합니다 - 그렇지 않으면 * 일반적으로 * 디자인을 다시 방문 할 수있는 좋은 지표입니다. 한 가지 덧붙여,'Monkey'는'IMonkeyRepository'에 의존하는 이유는 무엇입니까? –