Milestone 4 Requirements

Web Only

This textbook was authored for the CIS 400 - Object-Oriented Design, Implementation, and Testing course at Kansas State University. This section describes assignments specific to the Spring 2023 offering of that course. Prior semester offerings can be found here. If you are not enrolled in the course, please disregard this section.

For this milestone, you will be creating new classes representing an order and refactoring your existing classes to implement an interface and base classes. You will also need to update your unit tests to account for these changes. Finally, you will also create a UML class diagram to represent your classes.

General requirements:

  • You need to follow the style laid out in the C# Coding Conventions

  • You need to document your code using XML-style comments, with a minimum of <summary> tags, plus <param>, <returns>, and <exception> as appropriate.

Assignment requirements:

You will need to:

  • Create an IMenuItem interface to represent an item appearing on the menu

  • Refactor your existing classes to implement the IMenuItem interface

  • Add additional unit tests to verify your menu items can be treated as IMenuItem instances

  • Create an Order class to represent a collection of menu items being ordered together

  • Write unit tests to verify your new classes work as expected

  • Create a UML diagram for your Data Project

Purpose:

This milestone serves to introduce and utilize aspects of polymorphism including base classes, abstract base classes, abstract methods, virtual methods, method overriding, and interfaces. While the actual programming involved is straightforward, the concepts involved can be challenging to master. If you have any confusion after you have read the entire assignment please do not hesitate to reach out to a Professor Bean, the TAs, or your classmates over Discord.

IMenuItem Interface

You will create an interface named IMenuItem in the file IMenuItem.cs to represent the properties that all menu items share, which should include:

  • A get-only Name property of type string
  • A get-only Description property of type string
  • A get-only Price property of type decimal
  • A get-only Calories property of type uint
  • A get-only SpecialInstructions property of type IEnumerable<string>

You will need to implement this interface on all existing and future menu items defined in the Data project.

You will also want to test that your menu items can be cast to be an IMenuItem using the Assert.IsAssignableFrom<T>() assertion in the corresponding unit test file with a new Fact.

Abstract Base Classes

You will also write abstract base classes representing Entree, Side, and Drink menu items, in files named Entree.cs, Side.cs, and Drink.cs respectively. These should generalize (collect together) the properties that each of these categories of menu items have in common - either as abstract or virtual properties, to be overridden as needed in the derived classes.

All of your menu classes should be refactored to derive from one of these abstract base classes. Note that this may allow you to remove methods or require you to override the base method.

You will also want to test that your menu items can be cast to be the corresponding base class using the Assert.IsAssignableFrom<T>() assertion in the corresponding unit test file with a new Fact.

Drink Classes

You will also need to implement new classes representing the drinks available at The Flying Saucer, which are Liquified Vegetation, Saucer Fuel, and Inorganic Substance. All drinks have a Size property of type ServingSize, in addition to the normal IMenuItem properties.

Liquified Vegetation

PropertyAccessorsTypeValue
Nameget onlystring"Liquified Vegetation"
Descriptionget onlystring"A cold glass of blended vegetable juice."
Sizeget and setServingSizeDefault of `ServingSize.Small`
Iceget and setboolDefaults to true
Priceget onlydecimal$1.00 for small, $1.50 for medium, $2.00 for large
Caloriesget onlyuint72 for small, 144 for medium, 216 for large
SpecialInstructionsget onlyIEnumerable⟨string⟩Should include:
  • "No Ice" if Ice is false

Saucer Fuel

PropertyAccessorsTypeValue
Nameget onlystring"Saucer Fuel" or "Decaf Saucer Fuel" if Decaf is true
Descriptionget onlystring"A steaming cup of coffee."
Sizeget and setServingSizeDefault of `ServingSize.Small`
Decafget and setboolDefaults to false
Creamget and setboolDefaults to false
Priceget onlydecimal$1.00 for small, $1.50 for medium, $2.00 for large
Caloriesget onlyuint1 for small, 2 for medium, 3 for large, plus 29 calories for cream
SpecialInstructionsget onlyIEnumerable⟨string⟩Should include:
  • "With Cream" if Cream is true

Inorganic Substance

PropertyAccessorsTypeValue
Nameget onlystring"Inorganic Substance"
Descriptionget onlystring"A cold glass of ice water."
Sizeget and setServingSizeDefault of `ServingSize.Small`
Iceget and setboolDefaults to true
Priceget onlydecimal$0.00 for any size
Caloriesget onlyuint0 for all sizes
SpecialInstructionsget onlyIEnumerable⟨string⟩Should include:
  • "No Ice" if Ice is false

Order Class

You will also need to create a class, Order in a file Order.cs, representing an order containing multiple, potentially customized menu items. This class will need to implement the ICollection<IMenuItem> interface, allowing it to be treated as a collection. In addition to the methods and properties required for the interface, it should have the additional properties of:

  • Subtotal, a get-only decimal that is the price of all items in the order
  • TaxRate, a get/set decimal that represents the sales tax rate
  • Tax, a get-only decimal that is the tax for the order (Subtotal * TaxRate)
  • Total, a get-only decimal that is the sum of the Subtotal and Tax

Add Tests

Remember that your new classes (Order and all the drinks) will all need to have corresponding unit tests added to the DataTests project. Abstract classes Entree, Side, and Drink do not need to be tested, but any properties or methods inherited from them should be tested in the unit tests of the derived classes.

Note that for testing the Order class, you will want to use a mock object rather than your real menu item classes. This can be declared in the unit test class like this:

/// <summary>
/// A mock menu item for testing
/// </summary>
internal MockMenuItem : IMenuItem 
{
  public string Name {get; set;}
  public string Description {get; set;}
  public decimal Price {get; set;}
  public uint Calories {get; set;}
  public IEnumerable<string> SpecialInstructions {get;set;}
}

This allows you to initialize it with known values in a test, i.e. we might initialize four menu items with prices to test the Subtotal property:

[fact]
public SubtotalShouldReflectItemPrices()
{ 
  Order order = new Order();
  order.Add(new MockMenuItem() {Price = 1.00m});
  order.Add(new MockMenuItem() {Price = 2.50m});
  order.Add(new MockMenuItem() {Price = 3.00m});
  Assert.Equal(6.50m, order.Subtotal);
}

UML Class Diagram

Finally, you will need to create a UML class diagram for the Data project, and add it to your repository. This can be done with Visio or another visual editing program like Draw.io or Lucid Charts. You should save the diagram in a PDF or image format that the graders can view. You also will want to keep it in an editable format, as you’ll be updating it in future milestones. Be sure to follow the instructions in [Adding Documentation Files]https://textbooks.cs.ksu.edu/cis400/b-git-and-github/13-adding-documentation-files/ and double-check that the UML diagrams appear in your release.

Submitting the Assignment

Once your project is complete, merge your feature branch back into the main branch and create a release tagged v0.4.0 with name "Milestone 4". Copy the URL for the release page and submit it to the Canvas assignment.

Grading Rubric

The grading rubric for this assignment will be:

20% Structure Did you implement the structure as laid out in the specification? Are the correct names used for classes, enums, properties, methods, events, etc? Do classes inherit from expected base classes?

20% Documentation Does every class, method, property, and field use the correct XML-style documentation? Does every XML comment tag contain explanatory text? Is there a UML Diagram for the data project? Does the UML accurately reflect the structure of the project

20% Design Are you appropriately using C# to create reasonably efficient, secure, and usable software? Does your code contain bugs that will cause issues at runtime?

20% Functionality Does the program do what the assignment asks? Do properties return the expected values? Do methods perform the expected actions?

20% Tests Does the test suite include unit tests for all classes? Do the unit tests provide adequate coverage of the project?

Warning

Projects that do not compile will receive an automatic grade of 0.

Subsections of Milestone 4 Requirements

Subsections of Previous Versions

Milestone 4 Requirements (Fall 2022)

Web Only

This textbook was authored for the CIS 400 - Object-Oriented Design, Implementation, and Testing course at Kansas State University. This section describes assignments specific to the Fall 2022 offering of that course.

For this milestone, you will be creating unit tests for the menu item classes you have defined in the Data project. If these tests expose issues in your existing code, you will also want to fix them.

General requirements:

  • You need to follow the style laid out in the C# Coding Conventions

  • You need to document your code using XML-style comments, with a minimum of <summary> tags, plus <param>, <returns>, and <exception> as appropriate.

Assignment requirements:

You will need to:

  • Create a UML diagram for your Data Project

  • Refactor unit test class for PrehistoricPBJ to match its new specification

  • Create unit test classes for:

    • Brontowurst
    • DinoNuggets
    • PterodactylWings
    • VelociWraptor
    • AllosaurusAllAmericanBurger
    • CarnotaurusCheeseburger
    • DeinonychusDouble
    • TRexTripleBurger
    • Fryceritops
    • MeteorMacAndCheese
    • MezzorellaSticks
    • Triceritots
    • Plilosoda
    • CretaceousCoffee

In addition, if you did not declare your Burger base class abstract, you will need to create a unit test class for it.

Purpose:

This milestone serves to introduce the writing of unit tests. The real challenge of writing a unit test is not the programming involved, but rather, identifying what you need to test for. You should make sure that methods and properties behave as expected when used as expected. But you must also account for edge cases, where the objects are manipulated in unexpected ways. If you have any confusion after you have read the entire assignment please do not hesitate to reach out to a Professor Bean, the TAs, or your classmates over Discord.

Writing Tests

You will need to create an XUnit unit test class in your DataTests project for each menu item class in the Data project. These test classes must contain (at a minimum) the test methods described below. You may add additional methods.

In addition, when a test method takes parameters, you will need to provide corresponding [InlineData()] attributes to be used by the test runner as arguments for those parameters. You should supply enough attributes to either 1) be exhaustive (cover all possibilities), or 2) cover a reasonable number of expected cases and any edge cases.

Info

As a rule of thumb for this course, use at least 8 [InlineData()] options if there are more than 8 possible permutations. Good practice is to select these 8 largely at random (i.e. roll dice, use a random number generator, etc).

Refactor PrehistoricPBJUnitTests

The UnitTests/PrehistoricPBJ.cs already contains unit tests for the PrehistoricPBJ class, but these tests were for the original specification, not the refactoring you did for Milestone 1. As a result, you do not have a test of the Name property.

We know the name should always be “Prehistoric PBJ”. We could write a test in the form of a Fact to confirm this, i.e.:

[Fact]
public void NameShouldBeCorrect()
{
  PrehistoricPBJ pbj = new PrehistoricPBJ();
  Assert.Equal("Prehistoric PBJ", pbj.Name);
}

However, a stronger test would consider if changing other aspects of the PrehistoricPBJ object might change its name. A PrehistoricPBJ has three properties that can be customized: PeanutButter, Jelly, and Toasted. Using a Theory allows us to test different customizations, and ensure the name does not change:

[Theory]
[InlineData(true, true, true)]
[InlineData(true, true, false)]
[InlineData(true, false, true)]
[InlineData(false, true, true)]
[InlineData(false, false, true)]
[InlineData(true, false, false)]
[InlineData(false, false, false)]
public void NameShouldBeCorrect(bool peanutButter, bool jelly, bool toasted)
{
  PrehistoricPBJ pbj = new PrehistoricPBJ();
  pbj.PeanutButter = peanutButter;
  pbj.Jelly = jelly;
  pbj.Toasted = toasted;
  Assert.Equal("Prehistoric PBJ", pbj.Name);
}

Now the test ensures that even when we change aspects of how the PrehistoricPBJ is served, we still get the expected name. If the name did change, we could also specify what we expect the name as an additional argument/inline data. In fact, we can do that even if it doesn’t, i.e.:

[Theory]
[InlineData(true, true, true, "Prehistoric PBJ")]
[InlineData(true, true, false, "Prehistoric PBJ")]
[InlineData(true, false, true, "Prehistoric PBJ")]
[InlineData(false, true, true, "Prehistoric PBJ")]
[InlineData(false, false, true, "Prehistoric PBJ")]
[InlineData(true, false, false, "Prehistoric PBJ")]
[InlineData(false, false, false, "Prehistoric PBJ")]
public void NameShouldBeCorrect(bool peanutButter, bool jelly, bool toasted, string name)
{
  PrehistoricPBJ pbj = new PrehistoricPBJ();
  pbj.PeanutButter = peanutButter;
  pbj.Jelly = jelly;
  pbj.Toasted = toasted;
  Assert.Equal(name, pbj.Name);
}

In addition, the PrehistoricPBJ should now inherit from the base class Entree. We can check this with a simple Fact:

[Fact]
public void PrehistoricPBJShouldInheritFromEntree()
{
  PrehistoricPBJ pbj = new PrehistoricPBJ();
  Assert.IsAssignableFrom<Entree>(pbj);
}

This assertion checks that a PrehistoricPBJ can be cast as a Entree.

Write New Unit Tests

You need to write additional unit tests for the rest of the menu item classes. These should be placed in the DataTests project in the UnitTests folder, and named after the class they are testing, i.e. put the Dino Nuggets tests in DinoNuggetUnitTests.cs. This makes it easy to determine what class the test belongs to.

In the following sections is a list of minimum test methods you should add (you get to decide if they should be a [Fact] or [Theory]). Please use the names as written - that makes grading much faster. And remember, you can always add additional tests!

You can do operations within an [InlineData()], which may be helpful to keeping your numbers accurate. For example, consider an item with 480 calories, plus an additional 30 if it is served with a sauce. You can calculate the sum by hand, or express it as a sum in the [InlineData()], i.e:

[InlineData(ServingSize.Large, true, 480 + 130)]
BrontowurstUnitTests
  • ShouldInheritFromEntree
  • NameShouldBeCorrect
  • PriceShouldBeCorrect
  • CaloriesShouldBeCorrect
  • OnionsShouldDefaultToTrue
  • ShouldBeAbleToSetOnions
  • PeppersShouldDefaultToTrue
  • ShouldBeAbleToSetPeppers
DinoNuggetsUnitTests
  • ShouldInheritFromEntree
  • NameShouldBeCorrect
  • PriceShouldBeCorrect
  • CaloriesShouldBeCorrect
  • CountShouldDefaultToSix
  • ShouldBeAbleToSetCount
PterodactylWingsUnitTests
  • ShouldInheritFromEntree
  • NameShouldBeCorrect
  • PriceShouldBeCorrect
  • CaloriesShouldBeCorrect
  • SauceShouldDefaultToBuffalo
  • ShouldBeAbleToSetSauce
VelociWraptorUnitTests
  • ShouldInheritFromEntree
  • NameShouldBeCorrect
  • PriceShouldBeCorrect
  • CaloriesShouldBeCorrect
  • DressingShouldDefaultToTrue
  • ShouldBeAbleToSetDressing
  • CheeseShouldDefaultToTrue
  • ShouldBeAbleToSetCheese
AllosaurusAllAmericanBurgerUnitTests
  • ShouldInheritFromEntree
  • NameShouldBeCorrect
  • PriceShouldBeCorrect
  • CaloriesShouldBeCorrect
  • PattiesShouldDefaultToOne
  • ShouldBeAbleToSetPatties
  • KetchupShouldDefaultToTrue
  • ShouldBeAbleToSetKetchup
  • MustardShouldDefaultToTrue
  • ShouldBeAbleToSetMustard
  • PickleShouldDefaultToTrue
  • ShouldBeAbleToSetPickle
  • MayoShouldDefaultToFalse
  • ShouldBeAbleToSetMayo
  • BBQShouldDefaultToFalse
  • ShouldBeAbleToSetBBQ
  • OnionShouldDefaultToFalse
  • ShouldBeAbleToSetOnion
  • TomatoShouldDefaultToFalse
  • ShouldBeAbleToSetTomato
  • LettuceShouldDefaultToFalse
  • ShouldBeAbleToSetLettuce
  • AmericanCheeseShouldDefaultToFalse
  • ShouldBeAbleToSetAmericanCheese
  • SwissCheeseShouldDefaultToFalse
  • ShouldBeAbleToSetSwissCheese
  • BaconShouldDefaultToFalse
  • ShouldBeAbleToSetBacon
  • MushroomsShouldDefaultToFalse
  • ShouldBeAbleToSetMushrooms
CarnotaurusCheeseburgerUnitTests
  • ShouldInheritFromEntree
  • NameShouldBeCorrect
  • PriceShouldBeCorrect
  • CaloriesShouldBeCorrect
  • PattiesShouldDefaultToOne
  • ShouldBeAbleToSetPatties
  • KetchupShouldDefaultToTrue
  • ShouldBeAbleToSetKetchup
  • MustardShouldDefaultToFalse
  • ShouldBeAbleToSetMustard
  • PickleShouldDefaultToTrue
  • ShouldBeAbleToSetPickle
  • MayoShouldDefaultToFalse
  • ShouldBeAbleToSetMayo
  • BBQShouldDefaultToFalse
  • ShouldBeAbleToSetBBQ
  • OnionShouldDefaultToFalse
  • ShouldBeAbleToSetOnion
  • TomatoShouldDefaultToTrue
  • ShouldBeAbleToSetTomato
  • LettuceShouldDefaultToFalse
  • ShouldBeAbleToSetLettuce
  • AmericanCheeseShouldDefaultToTrue
  • ShouldBeAbleToSetAmericanCheese
  • SwissCheeseShouldDefaultToFalse
  • ShouldBeAbleToSetSwissCheese
  • BaconShouldDefaultToFalse
  • ShouldBeAbleToSetBacon
  • MushroomsShouldDefaultToFalse
  • ShouldBeAbleToSetMushrooms
DeinonychusDoubleUnitTests
  • ShouldInheritFromEntree
  • NameShouldBeCorrect
  • PriceShouldBeCorrect
  • CaloriesShouldBeCorrect
  • PattiesShouldDefaultToTwo
  • ShouldBeAbleToSetPatties
  • KetchupShouldDefaultToFalse
  • ShouldBeAbleToSetKetchup
  • MustardShouldDefaultToFalse
  • ShouldBeAbleToSetMustard
  • PickleShouldDefaultToTrue
  • ShouldBeAbleToSetPickle
  • MayoShouldDefaultToFalse
  • ShouldBeAbleToSetMayo
  • BBQShouldDefaultToTrue
  • ShouldBeAbleToSetBBQ
  • OnionShouldDefaultToTrue
  • ShouldBeAbleToSetOnion
  • TomatoShouldDefaultToFalse
  • ShouldBeAbleToSetTomato
  • LettuceShouldDefaultToFalse
  • ShouldBeAbleToSetLettuce
  • AmericanCheeseShouldDefaultToFalse
  • ShouldBeAbleToSetAmericanCheese
  • SwissCheeseShouldDefaultToTrue
  • ShouldBeAbleToSetSwissCheese
  • BaconShouldDefaultToFalse
  • ShouldBeAbleToSetBacon
  • MushroomsShouldDefaultToTrue
  • ShouldBeAbleToSetMushrooms
TRexTripleBurgerUnitTests
  • ShouldInheritFromEntree
  • NameShouldBeCorrect
  • PriceShouldBeCorrect
  • CaloriesShouldBeCorrect
  • PattiesShouldDefaultToThree
  • ShouldBeAbleToSetPatties
  • KetchupShouldDefaultToTrue
  • ShouldBeAbleToSetKetchup
  • MustardShouldDefaultToFalse
  • ShouldBeAbleToSetMustard
  • PickleShouldDefaultToTrue
  • ShouldBeAbleToSetPickle
  • MayoShouldDefaultToTrue
  • ShouldBeAbleToSetMayo
  • BBQShouldDefaultToFalse
  • ShouldBeAbleToSetBBQ
  • OnionShouldDefaultToTrue
  • ShouldBeAbleToSetOnion
  • TomatoShouldDefaultToTrue
  • ShouldBeAbleToSetTomato
  • LettuceShouldDefaultToTrue
  • ShouldBeAbleToSetLettuce
  • AmericanCheeseShouldDefaultToFalse
  • ShouldBeAbleToSetAmericanCheese
  • SwissCheeseShouldDefaultToFalse
  • ShouldBeAbleToSetSwissCheese
  • BaconShouldDefaultToFalse
  • ShouldBeAbleToSetBacon
  • MushroomsShouldDefaultToFalse
  • ShouldBeAbleToSetMushrooms
FryceritopsUnitTests
  • ShouldInheritFromSide
  • NameShouldBeCorrect
  • PriceShouldBeCorrect
  • CaloriesShouldBeCorrect
  • ShouldBeAbleToSetSize
  • SaltShouldDefaultToTrue
  • ShouldBeAbleToSetSalt
  • SauceShouldDefaultToFalse
  • ShouldBeAbleToSetSauce
MeteorMacAndCheeseUnitTests
  • ShouldInheritFromSide
  • NameShouldBeCorrect
  • PriceShouldBeCorrect
  • CaloriesShouldBeCorrect
  • ShouldBeAbleToSetSize
MezzorellaSticksUnitTests
  • ShouldInheritFromSide
  • NameShouldBeCorrect
  • PriceShouldBeCorrect
  • CaloriesShouldBeCorrect
  • ShouldBeAbleToSetSize
TriceritotsUnitTests
  • ShouldInheritFromSide
  • NameShouldBeCorrect
  • PriceShouldBeCorrect
  • CaloriesShouldBeCorrect
  • ShouldBeAbleToSetSize
PlilosodaUnitTests
  • ShouldInheritFromDrink
  • NameShouldBeCorrect
  • PriceShouldBeCorrect
  • CaloriesShouldBeCorrect
  • ShouldBeAbleToSetSize
  • ShouldBeAbleToSetFlavor
CretaceousCoffeeUnitTests
  • ShouldInheritFromDrink
  • NameShouldBeCorrect
  • PriceShouldBeCorrect
  • CaloriesShouldBeCorrect
  • ShouldBeAbleToSetSize
  • ShouldBeAbleToSetCream
  • CreamShouldDefaultToFalse

Refactoring Menu Item Classes

You may find in the process of writing your tests that your implementation of a particular menu item is not working correctly. If this is the case, congratulations! Your tests are doing their job!

At this point, you’ll want to refactor the corresponding class to fix any of these problems.

Submitting the Assignment

Once your project is complete, merge your feature branch back into the main branch and create a release tagged v0.4.0 with name "Milestone 4". Copy the URL for the release page and submit it to the Canvas assignment.

Grading Rubric

The grading rubric for this assignment will be:

25% Structure Did you implement the structure as laid out in the specification? Are the correct names used for classes, enums, properties, methods, events, etc? Do classes inherit from expected base classes?

25% Documentation Does every class, method, property, and field use the correct XML-style documentation? Does every XML comment tag contain explanatory text?

25% Design Are you appropriately using C# to create reasonably efficient, secure, and usable software? Does your code contain bugs that will cause issues at runtime?

25% Functionality Does the program do what the assignment asks? Do properties return the expected values? Do methods perform the expected actions?

Warning

Projects that do not compile will receive an automatic grade of 0.

Milestone 4 Requirements (Spring 2022)

Web Only

This textbook was authored for the CIS 400 - Object-Oriented Design, Implementation, and Testing course at Kansas State University. This section describes assignments specific to the Fall 2022 offering of that course. If you are not enrolled in the course, please disregard this section.

For this milestone, you will be creating unit tests for the menu item classes you have defined in the Data project. If these tests expose issues in your existing code, you will also want to fix them.

General requirements:

  • You need to follow the style laid out in the C# Coding Conventions

  • You will need to update your UML diagram to reflect any changes you make to the Data project.

Assignment requirements:

You will need to:

  • Refactor unit test class for AppleFritters to match its new specification

  • Create unit test classes for:

    • FriedPie
    • FriedIceCream
    • FriedCandyBar
    • FriedTwinkie
    • FriedBananas
    • FriedCheesecake
    • FriedOreos
    • Piper Platter
    • Popper Platter

Purpose:

This milestone serves to introduce the writing of unit tests. The real challenge of writing a unit test is not the programming involved, but rather, identifying what you need to test for. You should make sure that methods and properties behave as expected when used as expected. But you must also account for edge cases, where the objects are manipulated in unexpected ways. If you have any confusion after you have read the entire assignment please do not hesitate to reach out to a Professor Bean, the TAs, or your classmates over Discord.

Writing Tests

You will need to create an XUnit unit test class in your DataTests project for each men item class in the Data project. These test classes must contain (at a minimum) the test methods described below. You may add additional methods.

In addition, when a test method takes parameters, you will need to provide corresponding [InlineData()] attributes to be used by the test runner as arguments for those parameters. You should supply enough attributes to either 1) be exhaustive (cover all possibilities), or 2) cover a number of expected cases and any edge cases.

Info

As a rule of thumb for this course, use at least 8 [InlineData()] options if there are more than 8 possible permutations. Good practice is to select these 8 largely at random (i.e. roll dice, use a random number generator, etc).

Refactor AppleFrittersUnitTests

The UnitTests/AppleFrittersTests.cs already contains unit tests for the AppleFritters class, but these tests were for the original specification, not the refactoring you did for Milestone 3. As a result, some of these tests are not passing, and need to be refactored to meet the new specification.

For example, the value of the Name property is no longer always “AppleFritters”. Instead, it contains the size. So we need to refactor our NameShouldBeCorrect() method to respond to this potential change.

A good way to handle this is to switch from using a [Fact] to using a [Theory], and pass in the possible sizes as [InlineData]. In addition, it is a good practice to pass in the expected value (in this case, what we expect the name to be). This way, we can quickly visually verify the test expectations. The refactored method might look like this:

[Theory]
[InlineData(ServingSize.Small, "Small Apple Fritters")]
[InlineData(ServingSize.Medium, "Medium Apple Fritters")]
[InlineData(ServingSize.Large, "Large Apple Fritters")]
public void NameShouldBeCorrect(ServingSize size, string name)
{
    var fritters = new AppleFritters();
    fritters.Size = size;
    Assert.Equal(name, fritters.Name);
}

Note that we now need to include a using statement for the FriedPiper.Data.Enums namespace (using FriedPiper.Data.Enums) or else use the fully qualified name for ServingSize (FriedPiper.Data.Enums.ServingSize).

Likewise our Calories and Price properties need to change to reflect the new sizes available. These tests can be written as a [Theory] as well, again supplying a ServingSize and the expected values for Calories and Price.

But Calories is affected by two separate properties - Size and Glazed. Thus, we need to pass both to our test, along with the expected Calories value:

[Theory]
[InlineData(ServingSize.Small, true, 370)]
[InlineData(ServingSize.Medium, true, 490)]
[InlineData(ServingSize.Large, true, 610)]
[InlineData(ServingSize.Small, false, 240)]
[InlineData(ServingSize.Medium, false, 360)]
[InlineData(ServingSize.Large, false, 480)]
public void CaloriesShouldBeCorrect(ServingSize size, bool glazed, uint calories)
{
    var appleFritters = new AppleFritters();
    appleFritters.Size = size;
    appleFritters.Glazed = glazed;
    Assert.Equal(calories, appleFritters.Calories);
}

You can do operations within an [InlineData()], which may be helpful to keeping your numbers accurate. For example, a large apple fritters has 480 calories, plus an additional 130 if it is glazed. You can calculate the sum by hand, or express it as a sum in the [InlineData()]:

[InlineData(ServingSize.Large, true, 480 + 130)]

Finally, we want to add some tests to verify that the AppleFritters implements the IMenuItem interface and extends the Popper base class. This can be done with xUnit’s Assert.IsAssignableFrom<T>() assertion:

[Fact]
public void ShouldImplementIMenuItem()
{
    var fritters = new AppleFritters();
    Assert.IsAssignableFrom<IMenuItem>(fritters);
}

This tests that the fritter variable can be casted as a IMenuItem. You’ll also want to write a ShouldExtendPopper() test in the same way.

Write New Unit Tests

You need to write additional unit tests for the rest of the menu item classes. These should be placed in the DataTests project in the UnitTests folder, and named after the class they are testing, i.e. put the fried pie tests in FriedPieUnitTests.cs. This makes it easy to determine what class the test belongs to.

In the following sections is a list of minimum test methods you should add (you get to decide if they should be a [Fact] or [Theory]). Please use the names as written - that makes grading much faster. And remember, you can always add additional tests!

FriedPieUnitTests
  • ShouldImplementIMenuItem
  • ShouldBeAbleToSetPieFilling
  • ShouldBeNamedCorrectly
  • ShouldHaveCorrectPrice
  • ShouldHaveCorrectCalories
FriedIceCreamUnitTests
  • ShouldImplementIMenuItem
  • ShouldBeAbleToSetIceCreamFlavor
  • ShouldBeNamedCorrectly
  • ShouldHaveCorrectPrice
  • ShouldHaveCorrectCalories
FriedCandyBarUnitTests
  • ShouldImplementIMenuItem
  • ShouldBeAbleToSetCandyBar
  • ShouldBeNamedCorrectly
  • ShouldHaveCorrectPrice
  • ShouldHaveCorrectCalories
FriedTwinkieUnitTests
  • ShouldImplementIMenuItem
  • ShouldBeNamedCorrectly
  • ShouldHaveCorrectPrice
  • ShouldHaveCorrectCalories
FriedBananasUnitTests
  • ShouldImplementIMenuItem
  • ShouldExtendPopper
  • ShouldBeAbleToSetGlazed
  • ShouldBeNamedCorrectly
  • ShouldHaveCorrectPrice
  • ShouldHaveCorrectCalories
FriedCheesecakeUnitTests
  • ShouldImplementIMenuItem
  • ShouldExtendPopper
  • ShouldBeAbleToSetGlazed
  • ShouldBeNamedCorrectly
  • ShouldHaveCorrectPrice
  • ShouldHaveCorrectCalories
FriedOreosUnitTests
  • ShouldImplementIMenuItem
  • ShouldExtendPopper
  • ShouldBeAbleToSetGlazed
  • ShouldBeNamedCorrectly
  • ShouldHaveCorrectPrice
  • ShouldHaveCorrectCalories
PiperPlatterUnitTests
  • ShouldImplementIMenuItem
  • ShouldBeAbleToSetLeftPieFilling
  • ShouldBeAbleToSetRightPieFilling
  • ShouldBeAbleToSetLeftIceCreamFlavor
  • ShouldBeAbleToSetRightIceCreamFlavor
  • ShouldBeNamedCorrectly
  • ShouldHaveCorrectPrice
  • ShouldHaveCorrectCalories
PopperPlatterUnitTests
  • ShouldImplementIMenuItem
  • ShouldBeAbleToSetSize
  • SettingSizeShouldAlsoSetPopperSize
  • ShouldBeAbleToSetGlazed
  • SettingGlazedShouldAlsoSetPopperGlazed
  • ShouldBeNamedCorrectly
  • ShouldHaveCorrectPrice
  • ShouldHaveCorrectCalories

Refactoring Menu Item Classes

You may find in the process of writing your tests that your implementation of a particular menu item is not working correctly. If this is the case, congratulations! Your tests are doing their job!

At this point, you’ll want to refactor the corresponding class to fix any of these problems. If this involves making changes to the structure of the class, be sure to update your UML diagram as well!

Submitting the Assignment

Once your project is complete, merge your feature branch back into the main branch and create a release tagged v0.4.0 with name "Milestone 4". Copy the URL for the release page and submit it to the Canvas assignment.

Grading Rubric

The grading rubric for this assignment will be:

25% Structure Did you implement the structure as laid out in the specification? Are the correct names used for classes, enums, properties, methods, events, etc? Do classes inherit from expected base classes?

25% Documentation Does every class, method, property, and field use the correct XML-style documentation? Does every XML comment tag contain explanatory text?

25% Design Are you appropriately using C# to create reasonably efficient, secure, and usable software? Does your code contain bugs that will cause issues at runtime?

25% Functionality Does the program do what the assignment asks? Do properties return the expected values? Do methods perform the expected actions?

Warning

Projects that do not compile will receive an automatic grade of 0.