2012-09-02 2 views
2

나는 작업 병렬 라이브러리를 사용하여 화재를 구현하고 기능을 잊어 버리려고합니다. Task.Factory.StartNew에 대한 인라인 호출을 사용하면 모든 것이 예상대로 작동합니다. 그러나 Task.Factory.StartNew 호출을 별도의 클래스로 이동하여 로깅, 오류 처리 등을 추가 할 수 있으며 코드를 복제하지 않고 앞으로 더 나은 스레딩 클래스 등의 코드를 업그레이드 할 수 있으며 .NET Framework에 추가됩니다. .TPL 화재 및 별도의 클래스를 사용하여 잊어

다음은 내가 통과 할 것으로 예상되는 단위 테스트이지만, 그렇지 않습니다. 이 작업을 수행하는 방법을 파악하는 데 도움을 주시면 감사하겠습니다.

[TestFixture] 
public class ThreadingServiceFixture 
{ 
    public static bool methodFired = false; 

    [Test] 
    public void CanFireAndForgetWithThreadingService() 
    { 
     try 
     { 
      var service = new ThreadingService(); 

      service.FireAndForget(() => methodFired = true); 

      var endTime = DateTime.Now.AddSeconds(1); 

      while(DateTime.Now < endTime) 
      { 
       //wait 
      } 

      Assert.IsTrue(methodFired == true); 
     } 
     finally 
     { 
      methodFired = false; 
     }  
    } 

} 

public class ThreadingService 
{ 
    public Task FireAndForget(Action action) 
    { 
     return Task.Factory.StartNew(() => action); 
    } 
} 

답변

3

작업을 실행하지 않고 방금 반환합니다.

시도 :

return Task.Factory.StartNew(() => action()); 
+1

또는 'StartNew (action)'. – svick

+0

@svick - true :) –

2

당신은 코드가

public class ThreadingService 
{ 
    public Task FireAndForget(Action action) 
    { 
     return Task.Factory.StartNew(() => action.Invoke()); 
    } 
} 

추가 메모와 같은 뭔가를 읽어야 ThreadingService

에서 작업을 호출하지 않았다 : 공공 필드 상태를 테스트하는 것은 악이다. 반복성, 유지 보수, 다른 순서로 테스트 실행에 대해 생각해보십시오. 테스트 중에 bool methodFired으로 이동해야합니다. 또한 이것을 테스트하는 더 좋은 기술이 있다고 가정합니다 (그러나 어느 것이 확실하지 않습니다).

2

는 경우 발신자가 Task 것을 얻고 그것을 취소 할 수 있기 때문에 당신이 (즉, FireAndForget 방법에서 Task을 반환 할 필요가 없습니다 엄격하게 발신자는 것 말하고 "화재와 잊지"입니다 전화의 "기억").

ThreadingService에서 상속받지 않는 많은 서비스에서이 메서드를 호출하려면 인터페이스를 통해 확장 메서드를 구현할 수 있습니다.

public interface IFireAndForget 
{ 
    // no member needed. 
} 

public static class FireAndForgetExtensions 
{ 
    public static void FireAndForget(this IFireAndForget obj, Action action) 
    { 
     // pass the action, not a new lambda 
     Task.Factory.StartNew(action); 
    } 
} 


// using 
public class ThreadingService : IFireAndForget 
{ 

} 

또한 당신이 StartNew 방법에 action를 전달하는 action 매개 변수를 반환 람다 통과의 insted이 당신의 방법에주의.

+0

동의, 작업을 반환 코드의 특성을 감안할 때 나쁜 생각입니다. 디버깅 할 때 추가했지만 제거해야합니다. –

1

스레드 코드를 테스트하는 것은 어렵습니다. 타이밍 테스트를 수행하는 것은 좋지 않은 아이디어입니다. 결정적이지 않을 수 있으며 서버를 구축 할 때 엉뚱한 동작을 관찰 할 수 있습니다. 언젠가 패스하고 때로는 통과하지 못하는 테스트를 상상해보십시오!

코드를 실행하면 실제로 액션을 호출하지 않으므로 코드에 버그가 있습니다.

그러나이 변화를 고려해

[Test] 
[TimeOut(5000)] 
public void CanFireAndForgetWithThreadingService() 
{ 
    var service = new ThreadingService(); 
    ManualResetEvent mre = new ManualRestEvent(bool); // I never remember what is the default... 

    service.FireAndForget(() => mre.Set() /*will release the test asynchroneously*/); 
    mre.WaitOne(); // blocks, will timeout if FireAndForget does not fire the action. 
} 

예, 우리는 여전히 사용하고 타이밍을. 하지만 타임 아웃 테스트는 코드가 깨지는 경우에만 발생합니다! 다른 모든 시나리오에서 테스트는 절대적으로 예측 가능하며 실행에 매우 짧은 시간이 걸리므로 타이밍 문제가 발생하지 않도록 기다리고기도하지 않아도됩니다.

관련 문제