d2jsp
Log InRegister
d2jsp Forums > Off-Topic > Computers & IT > Programming & Development > Need Help On Unit Testing > A School Project
Add Reply New Topic New Poll
Member
Posts: 23,665
Joined: Jul 31 2009
Gold: 0.00
Mar 19 2014 08:10pm
Hi there,

Anyone here have any knowledge about unit testing for Visual Studio 2012? Our group project was to create a website that sells office supplies product. Our program are able to pull items from the database when user click add to cart. On checkout page, it shows the amount and price of each. Below is the code of the ShoppingCart model. I highlighted one of the method in bold and would like to get help on how I would test this method using unit testing that are included with Visual Studios 2012. Any particular help would be great!!


ShoppingCart.cs code:
------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace SeniorProject_PencilsnPen.Models
{
public class ShoppingCart
{
PencilsnPensEntities productDb = new PencilsnPensEntities();

string ShoppingCartId { get; set; }

public const string CartSessionKey = "CartId";

public static ShoppingCart GetCart(HttpContextBase context)
{
var cart = new ShoppingCart();
cart.ShoppingCartId = cart.GetCartId(context);
return cart;
}

// Helper method to simplify shopping cart calls
public static ShoppingCart GetCart(Controller controller)
{
return GetCart(controller.HttpContext);
}

public void AddToCart(Product product)
{
// Get the matching cart and album instances
var cartItem = productDb.Carts.SingleOrDefault(
c => c.CartId == ShoppingCartId
&& c.ProductId == product.ProductID);

if (cartItem == null)
{
// Create a new cart item if no cart item exists
cartItem = new Cart
{
ProductId = product.ProductID,
CartId = ShoppingCartId,
Count = 1,
DateCreated = DateTime.Now
};

productDb.Carts.Add(cartItem);
}
else
{
// If the item does exist in the cart, then add one to the quantity
cartItem.Count++;
}

// Save changes
productDb.SaveChanges();
}

public int RemoveFromCart(int id)
{
// Get the cart
var cartItem = productDb.Carts.Single(
cart => cart.CartId == ShoppingCartId
&& cart.ItemId == id);

int itemCount = 0;

if (cartItem != null)
{
if (cartItem.Count > 1)
{
cartItem.Count--;
itemCount = cartItem.Count;
}
else
{
productDb.Carts.Remove(cartItem);
}

// Save changes
productDb.SaveChanges();
}

return itemCount;
}

public void EmptyCart()
{
var cartItems = productDb.Carts.Where(cart => cart.CartId == ShoppingCartId);

foreach (var cartItem in cartItems)
{
productDb.Carts.Remove(cartItem);
}

// Save changes
productDb.SaveChanges();
}

public List<Cart> GetCartItems()
{
return productDb.Carts.Where(cart => cart.CartId == ShoppingCartId).ToList();
}

public int GetCount()
{
// Get the count of each item in the cart and sum them up
int? count = (from cartItems in productDb.Carts
where cartItems.CartId == ShoppingCartId
select (int?)cartItems.Count).Sum();

// Return 0 if all entries are null
return count ?? 0;
}

public decimal GetTotal()
{
// Multiply product price by count of that product to get
// the current price for each of those products in the cart
// sum all products price totals to get the cart total
decimal? total = (from cartItems in productDb.Carts
where cartItems.CartId == ShoppingCartId
select (int?)cartItems.Count * cartItems.Product.Price).Sum();
return total ?? decimal.Zero;
}

public int CreateOrder(Order order)
{
decimal orderTotal = 0;

var cartItems = GetCartItems();

// Iterate over the items in the cart, adding the order details for each
foreach (var item in cartItems)
{
var orderDetail = new OrderDetail
{
ProductID = item.ProductId,
OrderId = order.OrderId,
UnitPrice = item.Product.Price,
Quantity = item.Count
};

// Set the order total of the shopping cart
orderTotal += (item.Count * item.Product.Price);

productDb.OrderDetails.Add(orderDetail);

}


// Set the order's total to the orderTotal count
order.Total = orderTotal;

// Save the order
productDb.SaveChanges();

// Empty the shopping cart
EmptyCart();

// Return the OrderId as the confirmation number
return order.OrderId;
}

// Using HttpContextBase to allow access to cookies.
public string GetCartId(HttpContextBase context)
{
if (context.Session[CartSessionKey] == null)
{
if (!string.IsNullOrWhiteSpace(context.User.Identity.Name))
{
context.Session[CartSessionKey] = context.User.Identity.Name;
}
else
{
// Generate a new random GUID using System.Guid class
Guid tempCartId = Guid.NewGuid();

// Send tempCartId back to client as a cookie
context.Session[CartSessionKey] = tempCartId.ToString();
}
}

return context.Session[CartSessionKey].ToString();
}

// When a user has logged in, migrate their shopping cart to
// be associated with their username
public void MigrateCart(string userName)
{
var shoppingCart = productDb.Carts.Where(c => c.CartId == ShoppingCartId);

foreach (Cart item in shoppingCart)
{
item.CartId = userName;
}
productDb.SaveChanges();
}
}
}
Member
Posts: 1,995
Joined: Jun 28 2006
Gold: 7.41
Mar 19 2014 08:24pm
Something like this:

Code
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace UnitTesting
{
[TestClass]
public class UnitTester
{
[TestMethod]
public void TestCreateOrder()
{
Order o = new Order
{
//create new order with test data
};

ShoppingCart cart = new ShoppingCart
{
//create a shopping cart with test data
}

int result = cart.CreateOrder(o);

Assert.IsTrue(result == EXPECTED_VALUE_FOR_THIS_TEST_DATA);

}

}
}


Basically you will just want to create test input, feed it into the method, and then have assert statements around what you expected to get. You can go wild with the asserts. The more the merrier.
Member
Posts: 23,665
Joined: Jul 31 2009
Gold: 0.00
Mar 19 2014 09:24pm
This is what I did, thanks for the help. :thumbsup:

namespace ShoppingCart.Tests
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestCreateOrder()
{
//Arrange
double itemcount = 5;
double itemprice = 2.5;

//Act
double ordertotal = itemcount * itemprice;
double expectedtotal = 12.5;


//Assert
Assert.AreEqual(ordertotal, expectedtotal);
}
}
}
Member
Posts: 1,995
Joined: Jun 28 2006
Gold: 7.41
Mar 19 2014 09:30pm
Quote (2012xxxx @ Mar 19 2014 10:24pm)
This is what I did, thanks for the help.  :thumbsup:

namespace ShoppingCart.Tests
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestCreateOrder()
        {
            //Arrange
            double itemcount = 5;
            double itemprice = 2.5;

            //Act
            double ordertotal = itemcount * itemprice;
            double expectedtotal = 12.5;
           

            //Assert
            Assert.AreEqual(ordertotal, expectedtotal);
        }
    }
}


You aren't unit testing the method. The whole point of a unit test is to assert that what you expect to happen when you call a method actually does happen. You need to call the method...

All you are doing there is asserting that if you multiply 5 and 2.5 that it will be 12.5. That isn't a unit test for your CreateOrder method.

Member
Posts: 23,665
Joined: Jul 31 2009
Gold: 0.00
Mar 19 2014 09:34pm
I first had the expectedTotal to be any wild miscalculated number, so it gives me a failed when I ran the test. Is this what you're referring to (that I was suppose to do)? Sorry, I'm still very new.

This post was edited by 2012xxxx on Mar 19 2014 09:35pm
Member
Posts: 23,665
Joined: Jul 31 2009
Gold: 0.00
Mar 19 2014 09:39pm
So I need to call the method from my model (in this case, CreateOrder method)?
Member
Posts: 1,995
Joined: Jun 28 2006
Gold: 7.41
Mar 19 2014 09:42pm
Quote (2012xxxx @ Mar 19 2014 10:34pm)
I first had the expectedTotal to be any wild miscalculated number, so it gives me a failed when I ran the test. Is this what you're referring to (that I was suppose to do)? Sorry, I'm still very new.


The purpose of a unit test is to assert that the unit performs as it was expected.

What does CreateOrder actually do?

Code
public int CreateOrder(Order order)
{
decimal orderTotal = 0;

var cartItems = GetCartItems();

// Iterate over the items in the cart, adding the order details for each
foreach (var item in cartItems)
{
var orderDetail = new OrderDetail
{
ProductID = item.ProductId,
OrderId = order.OrderId,
UnitPrice = item.Product.Price,
Quantity = item.Count
};

// Set the order total of the shopping cart
orderTotal += (item.Count * item.Product.Price);

productDb.OrderDetails.Add(orderDetail);

}

// Set the order's total to the orderTotal count
order.Total = orderTotal;

// Save the order
productDb.SaveChanges();

// Empty the shopping cart
EmptyCart();

// Return the OrderId as the confirmation number
return order.OrderId;
}


Looking over this method...I can see that it is probably very most likely NOT actually creating an order. You aren't doing anything with the Order object you pass in. You are just setting Total on it and then returning the Order.Id. Why pass the Order into the method to begin with? Why not just construct the Order within the method and then return it?

In anycase, assuming it is correct, you want to Assert that the return of CreateOrder is the expected value. Did you modify Order by reference? Assert that the contents of Order is what you expected. Did CreateOrder modify the ShoppingCart? Assert the changes were what you expected (wouldn't do this...not technically a unit test).

Once you have you asserts set up, run the test. Do they pass? Yes? Then your unit is correct. Do they fail? Then your unit has bugs.


Member
Posts: 1,995
Joined: Jun 28 2006
Gold: 7.41
Mar 19 2014 09:43pm
Quote (2012xxxx @ Mar 19 2014 10:39pm)
So I need to call the method from my model (in this case, CreateOrder method)?


Dude, I gave you an example in my first post. I very explicitly called CreateOrder in that example...
Member
Posts: 23,665
Joined: Jul 31 2009
Gold: 0.00
Mar 19 2014 09:52pm
Quote (Minkomonster @ Mar 19 2014 08:43pm)
Dude, I gave you an example in my first post. I very explicitly called CreateOrder in that example...


Gotcha, I kind of see what you're saying. I'll get back with you on this. I'm gonna continue to work on it later. Thanks for the patient and help though!
Member
Posts: 1,995
Joined: Jun 28 2006
Gold: 7.41
Mar 19 2014 09:54pm
Quote (2012xxxx @ Mar 19 2014 10:52pm)
Gotcha, I kind of see what you're saying. I'll get back with you on this. I'm gonna continue to work on it later. Thanks for the patient and help though!


Good luck, let me know what you come up with. Post back with questions
Go Back To Programming & Development Topic List
Add Reply New Topic New Poll