使用Ninject进行Mocking和Dependency Injection的UnitTesting

时间:2016-06-08 16:20:22

标签: c# unit-testing dependency-injection ninject moq

我有以下场景,到目前为止我还没有使用过Ninject。我有以下类结构(简化以便于阅读:])。首先是所有IDocument s的抽象基类

public abstract class DocumentController : IDocumentController, IDisposable
{
    ...
    private IMessageBoxService messageBoxService;
    private IUndoRedoManager undoRedoManager;
    private FileSystemObserver observer;
    private bool fileChanging;

    public DocumentController(IMessageBoxService messageBoxService)
    {
        if (messageBoxService == null)
            throw new ArgumentNullException("messageBoxService");

        this.messageBoxService = messageBoxService;
    }
    ...
    private void FileChangedHandler(string p)
    {
        if (!fileChanging && p.CompareNoCase(FilePath))
        {
            fileChanging = true;
            try
            {
                (View as Form).UIThread(() =>
                {
                    DialogResult result = messageBoxService.DisplayMessage(
                        (Form)View,
                        String.Format(
                            MessageStrings.DocumentController_DocumentChanged,
                            FilePath,
                            Constants.Trademark),
                        CaptionStrings.ChangeNotification,
                        MessageBoxButtons.YesNo, MessageBoxIcon.Information);

                    if (result == DialogResult.Yes)
                    {
                        if (TryClose(new FormClosingEventArgs(CloseReason.None, false)))
                        {
                            MediatorService.Instance.NotifyColleagues(
                                MediatorService.Messages.OpenDocuments,
                                new List<string>() { FilePath });
                            Dispose();
                        }
                    }
                });
            }
            finally
            {
                fileChanging = false;
            }
        }
    }
    // Omitted code for not saved prompt for brevity.
}

此类监视所有打开的文档,如果在文件系统中更改它们,则会显示提示。如果在他们处于&#34;脏&#34;状态,相同IMessageBoxService提示保存。

派生的具体类ctors的一个例子是

public class TextEditorController : DocumentController, IZoom
{
    ...
    public TextEditorController(ITextEditorView view, IMessageBoxService messageBoxService) 
        : base(messageBoxService)
    {
        if (view == null)
            throw new ArgumentNullException("view");

        this.view = view;
        InitializeEventHandlers();
    }
    ...
}

现在使用该应用程序时效果很好。我遇到的问题是单元测试。我想要做的是编写一个单元测试,打开我的文本文档,进行一些更改,然后尝试关闭它们,如果它们是&#34;脏&#34; /未保存。这将显示一个消息框,但我想模拟IMessageBoxService并测试消息框是否确实在正确的条件下显示。我有以下单元测试类

[TestClass]
public class DocumentManagementTests
{
    private IDocumentProvider documentProvider;
    private Moq.Mock<IProgress<string>> mockProgress;
    private List<string> filePaths = new List<string>();

    #region Initialization.
    [TestInitialize]
    public void Initialize()
    {
        documentProvider = CompositionRoot.Resolve<IDocumentProvider>();
        if (documentProvider == null)
            throw new ArgumentNullException("documentManager");

        mockProgress = new Mock<IProgress<string>>();
        mockProgress.Setup(m => m.Report(It.IsAny<string>()))
             .Callback((string s) =>
             {
                 Trace.WriteLine(s);
             });

        LoadTextDocumentFilePaths();
    }

    private void LoadTextDocumentFilePaths()
    {
        // Add two real file paths to filePaths.
        Assert.AreEqual(2, filePaths.Count);
    }

    [TestMethod]
    public void DocumentChangedSavePromptTest()
    {
        // HOW DO I INJECT A MOCKED IMessageBoxService to `IDocumentController`?

        // Open the documents internally.
        var documents = documentProvider.GetDocumentViews(filePaths, mockProgress.Object);
        Assert.AreEqual(2, documentProvider.DocumentControllerCache
            .Count(d => d.GetType() == typeof(TextEditorController)));

        // Ammend the text internally. 
        foreach (var d in documentProvider.DocumentControllerCache)
        {
            var controller = d.Key as TextEditorController;

        }
        // Need to finish writing the test.
    }
}

所以我想知道如何将IMessageBoxService类的IDocumentController注入到[TestClass] public class DocumentManagementTests { private Mock<IProgress<string>> mockProgress; private Mock<IMessageBoxService> mockMessageBoxService; private int messageBoxInvocationCounter = 0; private List<string> filePaths = new List<string>(); [TestInitialize] public void Initialize() { // Progress mock. mockProgress = new Mock<IProgress<string>>(); mockProgress.Setup(m => m.Report(It.IsAny<string>())) .Callback((string s) => { Trace.WriteLine(s); }); Assert.IsNotNull(mockProgress); // Load the file paths. LoadTextDocumentFilePaths(); } private void LoadTextDocumentFilePaths() { string path = String.Empty; string directory = Utils.GetAssemblyDirectory(); foreach (var fileName in new List<string>() { "DocumentA.txt", "DocumentB.txt" }) { path = Path.Combine(directory, "Resources", "TextEditorDocs", fileName); if (!File.Exists(path)) throw new IOException($"{path} does not exist"); filePaths.Add(path); } Assert.AreEqual(2, filePaths.Count); } [TestMethod] public void DocumentChangedSavePrompt_OnUserClosing_Test() { // Message box service mock. mockMessageBoxService = new Mock<IMessageBoxService>(); mockMessageBoxService .Setup(m => m.DisplayMessage(It.IsAny<IWin32Window>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<MessageBoxButtons>(), It.IsAny<MessageBoxIcon>(), It.IsAny<MessageBoxDefaultButton>())) .Returns((IWin32Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton) => DialogResult.Cancel) .Callback((IWin32Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton) => { Trace.WriteLine("MockMessageBoxService Invoked"); messageBoxInvocationCounter++; }); Assert.IsNotNull(mockMessageBoxService); // Open the documents. List<TextEditorController> controllers = new List<TextEditorController>(); foreach (var path in filePaths) { TextEditorController controller = new TextEditorController( CompositionRoot.Resolve<ITextEditorView>(), mockMessageBoxService.Object); Assert.IsNotNull(controller); controllers.Add(controller); TextEditorView view = (TextEditorView)controller.Open(path); view.TextEditor.Text += "*"; Assert.IsTrue(controller.IsDirty); } // Test they are dirty and the message box is displayed. foreach (var controller in controllers) { bool didClose = controller.TryClose( new FormClosingEventArgs(CloseReason.UserClosing, false)); Assert.IsFalse(didClose); } Assert.AreEqual(2, messageBoxInvocationCounter); } } 类的ctor中?

感谢您的时间。

编辑。我提出的是以下测试方法。

TextEditorController

这是基于Stephen Ross的评论。我有什么理由不能创建具体的{{1}} s?

0 个答案:

没有答案