2010-01-03 2 views
2

Я хотел был бы иметь в состоянии высмеять класс ClientScriptManager на объекте страницы webforms, однако, кажется, что я не могу, я получаю ошибку, которую я не могу высмеять запечатанным класс.Создайте mock ClientScriptManager с Rhino Mocks

MockRepository mocks = new MockRepository() 

Page page = mocks.PartialMock<Page>(); 

var clientScript = mocks.PartialMock<ClientScriptManager>(); //error here 

SetupResult.For(page.ClientScript).Return(clientScript); 

Любой совет о том, как насмехаться над клиентом, будет оценен по достоинству.

ответ

4

Как вы обнаружили, вы не можете использовать большинство насмешливых библиотек для издевательства надпечатанных типов. Одной из причин этого является то, что многие макетные библиотеки работают, создавая производный тип, но если класс запечатан, то они не могут быть получены из него.

Что мы сделали внутренне в Microsoft является то, что мы используем IClientScriptManager интерфейса рукописного, а затем использовать ClientScriptManagerWrapper, который реализует этот интерфейс и делегируют все вызовы к реальным ClientScriptManager.

Тогда какой бы тип не нуждался в использовании ClientScriptManager, вместо него будет ссылка на IClientScriptManager. Во время выполнения мы создаем ClientScriptManagerWrapper (и переходим в реальный ClientScriptManager). Во время тестирования мы используем библиотеку макета для создания макета IClientScriptManager и используем это вместо этого.

А вот пример кода:

public class SomeClassThatNeedsClientScriptManager { 
    private IClientScriptManager _iClientScriptManager; 

    public IClientScriptManager IClientScriptManager { 
     get { 
      if (_iClientScriptManager == null) { 
       _iClientScriptManager = new ClientScriptManagerWrapper(Page.ClientScriptManager); 
      } 
      return _iClientScriptManager; 
     } 
     set { 
      _iClientScriptManager = value; 
     } 
    } 

    public void SomeMethodThatUsesClientScriptManager() { 
     IClientScriptManager.RegisterClientScriptBlock(typeof(Whatever), "key", "alert('hello')"); 
    } 
} 

public interface IClientScriptManager { 
    void RegisterClientScriptBlock(Type type, string key, string script); 
} 

public class ClientScriptManagerWrapper : IClientScriptManager { 
    private readonly ClientScriptManager _clientScriptManager; 

    public ClientScriptManagerWrapper(ClientScriptManager clientScriptManager) { 
     if (clientScriptManager == null) { 
      throw new ArgumentNullException("clientScriptManager"); 
     } 
     _clientScriptManager = clientScriptManager; 
    } 

    public void RegisterClientScriptBlock(Type type, string key, string script) { 
     _clientScriptManager.RegisterClientScriptBlock(type, key, script); 
    } 
} 

Вы можете изменить интерфейс IClientScriptManager и ClientScriptManagerWrapper иметь любые методы вам нужно.

+0

Слишком плохо, что это внутреннее. Мне бы хотелось увидеть больше типов Framework, реализующих общедоступные интерфейсы и обертки, чтобы тестируемый код мог взаимодействовать с меньшим количеством слоев. Но именно поэтому мы склонны обертывать обертки. :) – maxwellb

+0

@maxwellb действительно, если вы посмотрите на большинство новых фреймворков (конечно, в пространстве ASP.NET), вы увидите много больше интерфейсов и абстрактных базовых классов. Например, MVC, Web API и SignalR все используют интенсивное использование интерфейсов, что делает этот тип сценариев намного проще в реализации. – Eilon