I'm trying to grasp what's the idea behind TDD and how a team is supposed to work with it. I have the following test case with NUnit + Moq (just writing by memory, it is not assured the example compiles but it should be explanatory):
[Test]
public void WhenUserLogsCorrectlyIsRedirectedToLoginCorrectView() {
Mock<IUserDatabaseRepository> repoMock = new Mock<IUserDatabaseRepository>();
repoMock.Setup(m => m.GetUser(It.IsAny())).Returns(new User { Name = "Peter" });
Mock<ILoginHelper> loginHelperMock = new Mock<ILoginHelper>();
loginHelperMock.Setup(m => m.Login(It.IsAny(), It.IsAny())).Returns(true);
Mock<IViewModelFactory> factoryMock = new Mock<IViewModelFactory>();
factoryMock.Setup(m => m.CreateViewModel()).Returns(new LoginViewModel());
AccountController controller = new AccountController(repoMock.Object, loginHelperMock.Object, factoryMock.Object)
var result = controller.Index(username : "Peter", password: "whatever");
Assert.AreEqual(result.Model.Username, "Peter");
}
AccountController has 3 dependencies which I mock that, when orchestrated inside the controller, allows me to verify if a login was correct or not.
What stumbles my mind is that... if in TDD in theory you have to write first your test suite and build your code up from it, how am I supposed to know beforehand that in order to perform my operation I'll need to use those three dependencies and that the operation will call certain operations? It's like I need to know the innards of the Subject Under Test before even implementing it in order to Mock the dependencies and isolate the class, creating some kind of write test - write code - modify test if necessary cycle.
Naturally, without any knowledge of the innards of my code and just expressing the test, I could express it like it could just need the ILoginHelper and "magically" suppose before writing the code that it will return the user on a successful login (and ultimately realize that the underlying framework doesn't work that way, for instance returning just an ID instead of the full object).
Am I understanding TDD in an incorrect way? Which is a typical TDD practice on a complex case?
Thank you