TDD training always working in a circular relationship

I started using TDD to improve the quality and design of my code, but I usually run into a problem. I will try to explain this with a simple example: I am trying to implement a simple application using passive design. This means that I try to make the performance as stupid as possible. Consider an application in which a GUI has a button and a label. If the user clicks the button, the file is created with one random line in it. The label then indicates whether the creation was successful or not. The code might look like this:

  • IView Interface: One String String Property: Result
  • GUIEventListener class: OnUserButtonClick method called from a GUI button
  • FileSaver class: SaveFile method that is called from the GUIEventListener
  • GUIController class: UpdateLabel method that is called from the SaveFile method of the FileSaver class with a parameter that depends on the success of the SaveFile method.

Activation looks like this:

  • View ctor: View (GUIEventListener eventListener)
  • GUIEventListener ctor: GUIEventListener (FileSaver fileSaver)
  • FileSaver ctor: FileSaver (GUIController controller)
  • GUIController ctor: GUIController (view)

As you can clearly see, there is circular dependence in design. Usually I try to avoid using events, I donโ€™t like to test them, and I think this type of design is more explanatory, since it clearly indicates what the relation of classes is. I heard about the IoC design style, but I'm not very familiar with it.

" " TDD ? , , .

+5
3

GUIEventListener. , .

, , :

public interface IView
{
    void DisplayMessage(string message);
    void AddButtonClickHandler(Action handler);
}

FileSaver :

public interface IFileSaver
{
    Boolean SaveFileWithRandomLine(); 
}

, :

public interface IController
{ 

}

:

public class Controller : IController
{
    public Controller(IView view, IFileSaver fileSaver)
    {

    }
}

, ( NUnit Moq):

[TestFixture]
public class ControllerTest
{
    private Controller controller;
    private Mock<IFileSaver> fileSaver;
    private Mock<IView> view;
    private Action ButtonClickAction;

    [SetUp]
    public void SetUp()
    {
        view = new Mock<IView>();

        //Let store the delegate added to the view so we can invoke it later, 
        //simulating a click on the button
        view.Setup((v) => v.AddButtonClickHandler(It.IsAny<Action>()))
            .Callback<Action>((a) => ButtonClickAction = a);

        fileSaver = new Mock<IFileSaver>();

        controller = new Controller(view.Object, fileSaver.Object);

        //This tests if a handler was added via AddButtonClickHandler
        //via the Controller ctor.
        view.VerifyAll();         
    }

    [Test]
    public void No_button_click_nothing_happens()
    {
        fileSaver.Setup(f => f.SaveFileWithRandomLine()).Returns(true);

        view.Verify(v => v.DisplayMessage(It.IsAny<String>()), Times.Never());
    }

    [Test]
    public void Say_it_worked()
    {
        fileSaver.Setup(f => f.SaveFileWithRandomLine()).Returns(true);
        ButtonClickAction();

        view.Verify(v => v.DisplayMessage("It worked!"));
    }

    [Test]
    public void Say_it_failed()
    {
        fileSaver.Setup(f => f.SaveFileWithRandomLine()).Returns(false);
        ButtonClickAction();

        view.Verify(v => v.DisplayMessage("It failed!"));
    }
}

, , , Moq.

( , , , ):

public class Controller : IController
{
    public Controller(IView view, IFileSaver fileSaver)
    {
        view.AddButtonClickHandler(() => view.DisplayMessage(fileSaver.SaveFileWithRandomLine() ? "It worked!" : "It failed!"));
    }
}

, , View FileSaver. , .

( , - , ), . , , View WinForms, View. , .

FileSaver , . .

, . . View FileSaver.

. : " , , ?" . , , Save-Method FileSaver , .

CAB

0
  • GUIController: UpdateLabel, FileSaver SaveFile

...

  • FileSaver ctor: FileSaver ( GUIController)

. FileSaver , (: ), , .. , - .

TDD, , TDD , FileSaver, , (. ).

, , , TDD, .

+3

... MVC, .

Controllers can be easily checked for mode, because they are logical classes, like any other, and you can mock dependencies. User interfaces, especially for web applications, are much more complex. You can use tools like Selenium or WatiN but this is really integration / acceptance testing, not unit testing.

Here is another reading:

How to get started with Selenium Core and ASP.NET MVC

So you should check the actions of the ASP.NET MVC controller

Good luck

+2
source

All Articles