I know this post is quite old, but I thought it would be helpful to give a practical example of how UNIT testing can indeed assist SYSTEM design.
I have pasted below some code that I think answers this question from the OP:
TDD is based on unit tests.. and not the integration between objects...So how can it possibly result in a better design at the integration (i.e. inter-object) level.
One answer to this is to define and test the API of the entire system, by example, in a collection of mocks for all the units, based on interfaces (not implementations) BEFORE doing any implementation at all. Then write ALL the unit tests referring to this collection, and by definition the tests should all pass.
Continue tweaking the overall system design until happy with it, and then implement the interfaces one by one, in each case switching out the interface mock for the new class implementation and refactoring until it passes.
In the following example there are just two minimal interfaces called IUnit1 and IUnit2 and a class which is responsible for defining the API between them, called MockApi. There is then a test class with unit tests for the two units, each of which can run with either the mocked interface or the implementation when available. Finally there are implementations called Unit1 and Unit2.
This example uses Moq and XUnit, but obviously could apply to any platform.
using Moq;
using Xunit;
namespace TDD_with_API
{
public interface IUnit1
{
string GetMessage(IUnit2 unit2);
}
public interface IUnit2
{
string GetExclamation();
string Name { get; set; }
}
public class MockApi
{
public MockApi()
{
// SET UP THE MOCKS AND EXPOSE THEIR OBJECTS AS PROPERTIES:
var mock_unit1 = new Mock<IUnit1>();
Unit1 = mock_unit1.Object;
var mock_unit2 = new Mock<IUnit2>();
Unit2 = mock_unit2.Object;
// ..etc for all the units in the API
// DEFINE THE API BY EXAMPLE:
mock_unit2.Setup(u => u.GetExclamation()).Returns("Hello");
mock_unit2.Setup(u => u.Name).Returns("World");
mock_unit1.Setup(u => u.GetMessage(It.IsAny<IUnit2>()))
.Returns((IUnit2 u) => u.GetExclamation() + " " + u.Name + "!");
}
public IUnit1 Unit1 { get; set; }
public IUnit2 Unit2 { get; set; }
}
public class UnitTests
{
private MockApi _api;
public UnitTests()
{
_api = new MockApi();
}
[Theory]
[InlineData(true)] // Comment this line out until class implemented
[InlineData(false)]
public void Test_Unit1(bool testThisUnitForReal)
{
IUnit1 unitToTest = testThisUnitForReal ?
new Unit1() : _api.Unit1;
Assert.Equal(unitToTest.GetMessage(_api.Unit2), "Hello World!");
}
[Theory]
[InlineData(true)] // Comment this line out until class implemented
[InlineData(false)]
public void Test_Unit2(bool testThisUnitForReal)
{
IUnit2 unitToTest = testThisUnitForReal ?
new Unit2() : _api.Unit2;
Assert.Equal(unitToTest.GetExclamation(), "Hello");
Assert.Equal(unitToTest.Name, "World");
}
}
public class Unit1 : IUnit1
{
public string GetMessage(IUnit2 unit2)
{
return string.Format("{0} {1}!",
unit2.GetExclamation(),unit2.Name);
}
}
public class Unit2 : IUnit2
{
public string Name { get; set; } = "World";
public string GetExclamation()
{
return "Hello";
}
}
}