After six months, the team has produced a version of Wizbang Widget that adheres much more than originally to the
and other Principles like Loose Coupling. The component is much more integrable now, not only into AcquiCorp's product, but into pretty much any product that wants to use it. At the same time, due to the
, the Wizbang Component is much more testable.
The important parts of the final code are below, along with a table showing the improvements in this final version of the component. Compare and contrast the table below with the original table [EDITPOINT: LINK]. Also below are tests written against the code. Take a second: peruse the tests and think about how, or if, they could have been written against the original code. Also look at the code in this final version, and the code in the RuntimeCompositionApplication solution, and think about how the final version of code can integrate with the RuntimeCompositionApplication, compared to the original code.
The code for the final improvement to ACME Corporation's Wizbang Component can be found in the solution Monolithv4. A couple of things to note about that code:
[TestClass]
public class WizbangComponentUnitTests {
[ TestMethod]
public void WhenDoItAllIsCalledWithSomeParameterNotOutOfBoundsAndReferringToExistingAndConformingThingThenAppropriateLoggableEventsMustBeAnnounced() {
//Arrange
var mockRepository = new Mock< IThingRepository>();
var mockNoiseDeterminer = new Mock< INoiseDeterminer>();
var mockNoiseRecorder = new Mock< INoiseRecorder>();
var wizbangComponent = new WizbangComponent(
mockRepository.Object, mockNoiseDeterminer.Object, mockNoiseRecorder.Object);
var loggedEvents = new List< string>();
wizbangComponent.AddLoggingListener(
(ed, let) => loggedEvents.Add(let + " : " + ed));
mockRepository
.Setup(
mr => mr.GetThing( It.IsAny< string>()))
.Returns( new IThingToThing(new Thing {Name = "Test Thing" }));
mockNoiseDeterminer
.Setup(nd => nd.DetermineNoise( It.IsAny< IThing>()))
.Returns( string.Empty);
//Act
wizbangComponent.DoItAll( "1");
//Assert
Assert.AreEqual(
2, loggedEvents.Count,
"When DoItAll was called with someParameter not out of bounds, the appropriate Loggable Events were not announced.");
}
[ TestMethod]
public void WhenDoItAllIsCalledWithSomeParameterOutOfBoundsThenAppropriateLoggableEventsMustBeAnnounced() {
//Arrange
var mockRepository = new Mock< IThingRepository>();
var mockNoiseDeterminer = new Mock< INoiseDeterminer>();
var mockNoiseRecorder = new Mock< INoiseRecorder>();
var wizbangComponent = new WizbangComponent(
mockRepository.Object, mockNoiseDeterminer.Object, mockNoiseRecorder.Object);
var loggedEvents = new List< string>();
wizbangComponent.AddLoggingListener(
(ed, let) => loggedEvents.Add(let + " : " + ed));
mockRepository
.Setup(
mr => mr.GetThing( It.IsAny< string>()))
.Returns( new IThingToThing(new Thing { Name = "Test Thing" }));
mockNoiseDeterminer
.Setup(nd => nd.DetermineNoise( It.IsAny< IThing>()))
.Returns( string.Empty);
//Act
wizbangComponent.DoItAll( "outofbounds");
//Assert
Assert.AreEqual(
3, loggedEvents.Count,
"When DoItAll was called with someParameter out of bounds, the appropriate Loggable Events were not announced.");
}
[ TestMethod]
public void WhenDoItAllIsCalledWithSomeParameterForNonexistentThingThenAppropriateLoggableEventsMustBeAnnounced() {
//Arrange
var mockRepository = new Mock< IThingRepository>();
var mockNoiseDeterminer = new Mock< INoiseDeterminer>();
var mockNoiseRecorder = new Mock< INoiseRecorder>();
var wizbangComponent = new WizbangComponent(
mockRepository.Object, mockNoiseDeterminer.Object, mockNoiseRecorder.Object);
var loggedEvents = new List< string>();
wizbangComponent.AddLoggingListener(
(ed, let) => loggedEvents.Add(let + " : " + ed));
mockRepository
.Setup(
mr => mr.GetThing( It.IsAny< string>()))
.Returns( null as IThing);
//Act
wizbangComponent.DoItAll( "1");
//Assert
Assert.AreEqual(
2, loggedEvents.Count,
"When DoItAll was called with someParameter referring to a nonexistent Thing, the appropriate Loggable Events were not announced.");
}
[ TestMethod]
public void WhenDoItAllIsCalledWithSomeParameterForNonconformingThingThenAppropriateLoggableEventsMustBeAnnounced() {
//Arrange
var mockRepository = new Mock< IThingRepository>();
var mockNoiseDeterminer = new Mock< INoiseDeterminer>();
var mockNoiseRecorder = new Mock< INoiseRecorder>();
var wizbangComponent = new WizbangComponent(
mockRepository.Object, mockNoiseDeterminer.Object, mockNoiseRecorder.Object);
var loggedEvents = new List< string>();
wizbangComponent.AddLoggingListener(
(ed, let) => loggedEvents.Add(let + " : " + ed));
mockRepository
.Setup(
mr => mr.GetThing( It.IsAny< string>()))
.Returns( new IThingToThing(new Thing {Name = "noconform" }));
mockNoiseDeterminer
.Setup(nd => nd.DetermineNoise( It.IsAny< IThing>()))
.Returns( string.Empty);
//Act
wizbangComponent.DoItAll( "1");
//Assert
Assert.AreEqual(
3, loggedEvents.Count,
"When DoItAll was called with someParameter fo, the appropriar a nonconforming thing, the appropriate Loggable Events were not announced.");
}
[ TestMethod]
public void WhenDoItAllIsCalledWithSomeParameterNotOutOfBoundsAndReferringToExistingAndConformingThingThenAppropriateBroadcastableEventsMustBeAnnounced() {
//Arrange
var mockRepository = new Mock< IThingRepository>();
var mockNoiseDeterminer = new Mock< INoiseDeterminer>();
var mockNoiseRecorder = new Mock< INoiseRecorder>();
var wizbangComponent = new WizbangComponent(
mockRepository.Object, mockNoiseDeterminer.Object, mockNoiseRecorder.Object);
var events = new List< string>();
wizbangComponent.AddListener(ed => events.Add(ed));
mockRepository
.Setup(
mr => mr.GetThing( It.IsAny< string>()))
.Returns( new IThingToThing(new Thing { Name = "Test Thing" }));
mockNoiseDeterminer
.Setup(nd => nd.DetermineNoise( It.IsAny< IThing>()))
.Returns( string.Empty);
//Act
wizbangComponent.DoItAll( "1");
//Assert
Assert.AreEqual(
2, events.Count,
"When DoItAll was called with someParameter not out of bounds, the appropriate Broadcastable Events were not announced.");
}
[ TestMethod]
public void WhenDoItAllIsCalledAndExceptionOccursThenAppropriateLoggableEventsMustBeAnnounced() {
//Arrange
var mockRepository = new Mock< IThingRepository>();
var mockNoiseDeterminer = new Mock< INoiseDeterminer>();
var mockNoiseRecorder = new Mock< INoiseRecorder>();
var wizbangComponent = new WizbangComponent(
mockRepository.Object, mockNoiseDeterminer.Object, mockNoiseRecorder.Object);
var loggedEvents = new List< string>();
wizbangComponent.AddLoggingListener(
(ed, let) => loggedEvents.Add(let + " : " + ed));
mockRepository
.Setup(
mr => mr.GetThing( It.IsAny< string>()))
.Throws( new Exception( "Fake Exception"));
//Act
try {
wizbangComponent.DoItAll( "1");
}
catch {
//For testing, we'll swallow this exception.
}
finally {
//Assert
Assert.AreEqual(
2, loggedEvents.Count,
"When DoItAll was called with someParameter not out of bounds, the appropriate Broadcastable Events were not announced.");
}
}
[ TestMethod]
public void WhenDoItAllIsCalledAndExceptionOccursThenAppropriateBroadcastableEventsMustBeAnnounced() {
//Arrange
var mockRepository = new Mock< IThingRepository>();
var mockNoiseDeterminer = new Mock< INoiseDeterminer>();
var mockNoiseRecorder = new Mock< INoiseRecorder>();
var wizbangComponent = new WizbangComponent(
mockRepository.Object, mockNoiseDeterminer.Object, mockNoiseRecorder.Object);
var events = new List< string>();
wizbangComponent.AddListener(ed => events.Add(ed));
mockRepository
.Setup(
mr => mr.GetThing( It.IsAny< string>()))
.Throws( new Exception( "Fake Exception"));
//mockNoiseDeterminer
// .Setup(nd => nd.DetermineNoise(It.IsAny<IThing>()))
// .Returns(string.Empty);
//Act
try {
wizbangComponent.DoItAll( "1");
}
catch {
//For testing, we'll swallow this exception.
}
finally {
//Assert
Assert.AreEqual(
1, events.Count,
"When DoItAll was called with someParameter not out of bounds, the appropriate Broadcastable Events were not announced.");
}
}
[ TestMethod]
public void WhenDoItAllIsCalledWithSomeParameterOutOfBoundsThenAppropriateBroadcastableEventsMustBeAnnounced() {
//Arrange
var mockRepository = new Mock< IThingRepository>();
var mockNoiseDeterminer = new Mock< INoiseDeterminer>();
var mockNoiseRecorder = new Mock< INoiseRecorder>();
var wizbangComponent = new WizbangComponent(
mockRepository.Object, mockNoiseDeterminer.Object, mockNoiseRecorder.Object);
var events = new List< string>();
wizbangComponent.AddListener(ed => events.Add(ed));
mockRepository
.Setup(
mr => mr.GetThing( It.IsAny< string>()))
.Returns( new IThingToThing(new Thing { Name = "Test Thing" }));
mockNoiseDeterminer
.Setup(nd => nd.DetermineNoise( It.IsAny< IThing>()))
.Returns( string.Empty);
//Act
wizbangComponent.DoItAll( "outofbounds");
//Assert
Assert.AreEqual(
2, events.Count,
"When DoItAll was called with someParameter out of bounds, the appropriate Broadcastable Events were not announced.");
}
[ TestMethod]
public void WhenDoItAllIsCalledWithSomeParameterForNonexistentThingThenAppropriateBroadcastableEventMustBeAnnounced() {
//Arrange
var mockRepository = new Mock< IThingRepository>();
var mockNoiseDeterminer = new Mock< INoiseDeterminer>();
var mockNoiseRecorder = new Mock< INoiseRecorder>();
var wizbangComponent = new WizbangComponent(
mockRepository.Object, mockNoiseDeterminer.Object, mockNoiseRecorder.Object);
var events = new List< string>();
wizbangComponent.AddListener(ed => events.Add(ed));
mockRepository
.Setup(
mr => mr.GetThing( It.IsAny< string>()))
.Returns( null as IThing);
//Act
wizbangComponent.DoItAll( "1");
//Assert
Assert.AreEqual(
1, events.Count,
"When DoItAll was called with someParameter referring to a nonexistent Thing, the appropriate Broadcastable Events were not announced.");
}
[ TestMethod]
public void WhenDoItAllIsCalledWithSomeParameterForNonconformingThingThenAppropriateBroadcastableEventsMustBeAnnounced() {
//Arrange
var mockRepository = new Mock< IThingRepository>();
var mockNoiseDeterminer = new Mock< INoiseDeterminer>();
var mockNoiseRecorder = new Mock< INoiseRecorder>();
var wizbangComponent = new WizbangComponent(
mockRepository.Object, mockNoiseDeterminer.Object, mockNoiseRecorder.Object);
var events = new List< string>();
wizbangComponent.AddListener(ed => events.Add(ed));
mockRepository
.Setup(
mr => mr.GetThing( It.IsAny< string>()))
.Returns( new IThingToThing(new Thing { Name = "noconform" }));
mockNoiseDeterminer
.Setup(nd => nd.DetermineNoise( It.IsAny< IThing>()))
.Returns( string.Empty);
//Act
wizbangComponent.DoItAll( "1");
//Assert
Assert.AreEqual(
2, events.Count,
"When DoItAll was called with someParameter foeventsr a nonconforming thing, the appropriate Broadcastable Events were not announced.");
}
private struct LoggedEvent {
internal LogEventType EventType { get ; set ; }
internal string EventDescription { get; set; }
}
[ TestMethod]
public void WhenDoItAllIsCalledWithAThingIdReferringToAThingThatBurpsThenALoggableEventMustBeAnnounced() {
//Arrange
var mockRepository = new Mock< IThingRepository>();
var mockNoiseDeterminer = new Mock< INoiseDeterminer>();
var mockNoiseRecorder = new Mock< INoiseRecorder>();
var wizbangComponent = new WizbangComponent(
mockRepository.Object, mockNoiseDeterminer.Object, mockNoiseRecorder.Object);
var loggableEvents = new List< LoggedEvent>();
wizbangComponent.AddLoggingListener(
(ed, let) => loggableEvents.Add(
new LoggedEvent { EventType = let, EventDescription = ed }));
mockRepository
.Setup(
mr => mr.GetThing( It.IsAny< string>()))
.Returns( new IThingToThing(new Thing { Name = "1" }));
mockNoiseDeterminer
.Setup(nd => nd.DetermineNoise( It.IsAny< IThing>()))
.Returns( "Burp!!!");
//Act
wizbangComponent.DoItAll( "1");
//Assert
Assert.IsTrue(
loggableEvents
.Any(
le => le.EventType == LogEventType.WARNING
&&
le.EventDescription.ToLower().Contains( "inappropriate noise")),
"When DoItAll was called with someParameter for a nonconforming thing, " +
"the appropriate Broadcastable Events were not announced." );
}
}