Business layer

You might want to start thinking about how to organize your tests effectively. As your application grows, and the number of test files increases, you may find it more and more cumbersome to navigate your solution. One answer might be to create individual folders per class under test and a single file per public method within the class folder. This might look something like this:

SpeakerService -> Search

You don't necessarily need to tackle this now, but it wouldn't hurt to have a plan for the future. Applications tend to grow quite quickly, and before you know it you will have thirteen projects within your solution. You may choose to go ahead and create a Services project with a ServicesTest project at this time, to separate your business layer and associated tests from your presentation layer and its tests. That will be left as an exercise for the reader.

Now, create a new test class for the SpeakerService. Here is where you'll be creating all of your test methods for Search in the SpeakerService:

[Fact]
public void ItExists()
{
var speakerService = new SpeakerService();
}

Once you make this test pass, create a few new tests to confirm the Search method exists and that it returns a collection of speakers:

[Fact]
public void ItHasSearchMethod()
{
var speakerService = new SpeakerService();

speakerService.Search("test");
}

Next, test that the SpeakerService implements the ISpeakerService interface:

[Fact]
public void ItImplementsISpeakerService()
{
var speakerService = new SpeakerService();

Assert.True(speakerService is ISpeakerService);
}

Your SpeakerService should now look something like this:

public class SpeakerService : ISpeakerService
{
public IEnumerable<Speaker> Search(string searchString)
{
return new List<Speaker>();
}
}

Remember, take slow and methodical steps. You are not allowed to write a line of production code without writing a failing test, and you're not to write more production code than is sufficient to make the tests pass.

Now, begin to move the skipped tests from the controller test file to the Speaker Service Search Test file. Start with GivenExactMatchThenOneSpeakerInCollection:

[Fact]
public void GivenExactMatchThenOneSpeakerInCollection()
{
// Arrange
// Act
var result = _speakerService.Search("Joshua");

// Assert
var speakers = result.ToList();
Assert.Equal(1, speakers.Count);
Assert.Equal("Joshua", speakers[0].Name);
}

Make this test pass, then move on to GivenCaseInsensitveMatchThenSpeakerInCollection:

[Theory]
[InlineData("Joshua")]
[InlineData("joshua")]
[InlineData("JoShUa")]
public void GivenCaseInsensitveMatchThenSpeakerInCollection(string searchString)
{
// Arrange
// Act
var result = _speakerService.Search(searchString);

// Assert
var speakers = result.ToList();
Assert.Equal(1, speakers.Count);
Assert.Equal("Joshua", speakers[0].Name);
}

And finally, GivenNoMatchThenEmptyCollection and Given3MatchThenCollectionWith3Speakers:

[Fact]
public void GivenNoMatchThenEmptyCollection()
{
// Arrange
// Act
var result = _speakerService.Search("ZZZ");

// Assert
var speakers = result.ToList();
Assert.Equal(0, speakers.Count);
}

[Fact]
public void Given3MatchThenCollectionWith3Speakers()
{
// Arrange
// Act
var result = _speakerService.Search("jos");

// Assert
var speakers = result.ToList();
Assert.Equal(3, speakers.Count);
Assert.True(speakers.Any(s => s.Name == "Josh"));
Assert.True(speakers.Any(s => s.Name == "Joshua"));
Assert.True(speakers.Any(s => s.Name == "Joseph"));
}

As you get more comfortable with the practice and gain more experience with TDD, you may find it helpful to list the tests which you want to implement. This could be simply jotting them down on a piece of paper, or stubbing out some skipped or ignored tests in your IDE.

If done correctly, your code should look something like this:

public class SpeakerService : ISpeakerService
{
public IEnumerable<Speaker> Search(string searchString)
{
var hardCodedSpeakers = new List<Speaker>
{
new Speaker{Name = "Josh"},
new Speaker{Name = "Joshua"},
new Speaker{Name = "Joseph"},
new Speaker{Name = "Bill"},
};

var speakers = hardCodedSpeakers.Where(x =>
x.Name.StartsWith(searchString,
StringComparison.OrdinalIgnoreCase)).ToList();

return speakers;
}
}

We’ve now moved the hard-coded data out of our controller and into our business layer in the SpeakerService. You may think that a lot of effort was expended simply to move the problem into a new file! While this is true to an extent, this actually puts us in a better place for future development. The "logic", such as it is, has been moved into a class that can be reused by other parts of the application, and by potential new interfaces (think native and/or mobile applications) that would not have access to our original controller.

We'll continue with this example in future chapters. We will finally rid ourselves of hard-coded data and implement a data access layer using the Entity framework. All of this can be accomplished with Test-Driven Development.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.138.170.174