Amazon Ad

Saturday 12 July 2014

Creating Fault Injections For ASP.NET MVC Web API

Hi Guys,

I was working on a new project which was having a challenge to create fault injection in a running Web API.

Step 1 : Create a model Class name "User"

public class User
    {
        public int Id { get; set; }
        public string Email { get; set; }
        public string Password { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Gender { get; set; }
    }





Step 2: Create an app context interface class with name IStoreAppContext.cs

public interface IStoreAppContext : IDisposable
    {
        DbSet<User> Users { get; }
        int SaveChanges();
        void MarkAsModifiedUser(User user);
    }

Step 3 : Create another class for app context with name StoreAppContext.cs

public class StoreAppContext : DbContext, IStoreAppContext
    {
        public StoreAppContext() : base("name=StoreAppContext")
        {
        }
        public System.Data.Entity.DbSet<StoreApp.Models.User> Users { get; set; }
        public void MarkAsModifiedUser(User user)
        {
            Entry(user).State = EntityState.Modified;
        }
    }

Step 4: Create an api controller with name "UserController" having the following code

       public class UserController : ApiController
    {
        private IStoreAppContext db = new StoreAppContext();

        public UserController() { }

        public UserController(IStoreAppContext context)
        {
            db = context;
        }

        // GET: api/Users
        public IQueryable<User> GetUsers()
        {
            //var u = (from p in db.Users where p.Email == user.Email && p.Password == user.Password select p).FirstOrDefault();
            return db.Users;
        }

        // GET: api/Users/5
        [ResponseType(typeof(User))]
        public IHttpActionResult GetUser(int id)
        {
            User user = db.Users.Find(id);
            if (user == null)
            {
                return NotFound();
            }

            return Ok(user);
        }

        // PUT: api/Users/5
        [ResponseType(typeof(void))]
        public IHttpActionResult PutUser(int id, User user)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            if (id != user.Id)
            {
                return BadRequest();
            }

            //db.Entry(user).State = EntityState.Modified;
            db.MarkAsModifiedUser(user);

            try
            {
                db.SaveChanges();
            }
            catch (DbUpdateConcurrencyException)
            {
                if (!UserExists(id))
                {
                    return NotFound();
                }
                else
                {
                    throw;
                }
            }

            return StatusCode(HttpStatusCode.NoContent);
        }

        // POST: api/Users
        [ResponseType(typeof(User))]
        public IHttpActionResult PostUser(User user)
        {
            if (user == null)
            {
                return BadRequest(ModelState);
            }
            else if (user.Id == -1)
            {
                var u = (from p in db.Users where p.Email == user.Email && p.Password == user.Password select p).FirstOrDefault();
                user = u;
            }
            else
            {
                if (!ModelState.IsValid || user == null || user.Email == null || user.Email == "" || user.Password == null || user.Password == "" || user.FirstName == null || user.FirstName == "" || user.LastName == null || user.LastName == "" || user.Gender == null || user.Gender == "" || (user.Gender != "Male" && user.Gender != "Female") || user.Password.Length <= 7)
                {
                    return BadRequest(ModelState);
                }

                Regex regex = new Regex(@"[\w-\.]+@([\w-]+\.)+[\w-]{2,4}");
                Regex regexString = new Regex(@"[A-Z][a-z]+");
                if (!regex.IsMatch(user.Email) || !regexString.IsMatch(user.FirstName) || !regexString.IsMatch(user.LastName))
                {
                    return BadRequest(ModelState);
                }

                db.Users.Add(user);
                db.SaveChanges();
            }
            return CreatedAtRoute("DefaultApi", new { id = user.Id }, user);
        }

        // DELETE: api/Users/5
        [ResponseType(typeof(User))]
        public IHttpActionResult DeleteUser(int id)
        {
            User user = db.Users.Find(id);
            if (user == null)
            {
                return NotFound();
            }

            db.Users.Remove(user);
            db.SaveChanges();

            return Ok(user);
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                db.Dispose();
            }
            base.Dispose(disposing);
        }

        private bool UserExists(int id)
        {
            return db.Users.Count(e => e.Id == id) > 0;
        }
    }

Step 5 : Now create another project (Unit Test Project) in your visual studio solution. 

Add references of
a. System.Web.Http.dll (version 5.2.0)
b. System.Web.Http.WebHost.dll (version 5.2.0)

you can get both of these from nuget.

Step 6 : Create a class with name "TestDbset.cs" having following code

public class TestDbSet<T> : DbSet<T>, IQueryable, IEnumerable<T>
        where T : class
    {
        ObservableCollection<T> _data;
        IQueryable _query;

        public TestDbSet()
        {
            _data = new ObservableCollection<T>();
            _query = _data.AsQueryable();
        }

        public override T Add(T item)
        {
            _data.Add(item);
            return item;
        }

        public override T Remove(T item)
        {
            _data.Remove(item);
            return item;
        }

        public override T Attach(T item)
        {
            _data.Add(item);
            return item;
        }

        public override T Create()
        {
            return Activator.CreateInstance<T>();
        }

        public override TDerivedEntity Create<TDerivedEntity>()
        {
            return Activator.CreateInstance<TDerivedEntity>();
        }

        public override ObservableCollection<T> Local
        {
            get { return new ObservableCollection<T>(_data); }
        }

        Type IQueryable.ElementType
        {
            get { return _query.ElementType; }
        }

        System.Linq.Expressions.Expression IQueryable.Expression
        {
            get { return _query.Expression; }
        }

        IQueryProvider IQueryable.Provider
        {
            get { return _query.Provider; }
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return _data.GetEnumerator();
        }

        IEnumerator<T> IEnumerable<T>.GetEnumerator()
        {
            return _data.GetEnumerator();
        }
    }

Step 7 : Create a class with name "TestUserController" having the following code

[TestClass]
    public class TestUserController
    {
        [TestMethod]
        public void PostUser_ShouldReturnSameUser()
        {
            var controller = new UserController(new TestStoreAppContext());

            var item = GetDemoUser();

            var result =
                controller.PostUser(item) as CreatedAtRouteNegotiatedContentResult<User>;

            Assert.IsNotNull(result);
            Assert.AreEqual(result.RouteName, "DefaultApi");
            Assert.AreEqual(result.RouteValues["id"], result.Content.Id);
            Assert.AreEqual(result.Content.FirstName, item.FirstName);
            Assert.AreEqual(result.Content.LastName, item.LastName);
            Assert.AreEqual(result.Content.Email, item.Email);
            Assert.AreEqual(result.Content.Password, item.Password);
            Assert.AreEqual(result.Content.Gender, item.Gender);
        }

        [TestMethod]
        public void PostUser_ShouldCheckEmptyStringValuesInUser()
        {
            var controller = new UserController(new TestStoreAppContext());

            var item = GetDemoUser();
            item.Email = "";
            item.Password = "";
            item.FirstName = "";
            item.LastName = "";
            item.Gender = "";

            var result =
                controller.PostUser(item) as CreatedAtRouteNegotiatedContentResult<User>;

            Assert.IsNull(result);
        }

        [TestMethod]
        public void PostUser_ShouldCheckNumberInStringValuesInUser()
        {
            var controller = new UserController(new TestStoreAppContext());

            var item = GetDemoUser();
            item.Email = "abc@abc.com";
            item.Password = "33777773";
            item.FirstName = "33";
            item.LastName = "333";
            item.Gender = "Male";

            var result =
                controller.PostUser(item) as CreatedAtRouteNegotiatedContentResult<User>;

            Assert.IsNull(result);
        }

        [TestMethod]
        public void PostUser_ShouldPasswordValuesInUser()
        {
            var controller = new UserController(new TestStoreAppContext());

            var item = GetDemoUser();
            item.Password = "";

            var result =
                controller.PostUser(item) as CreatedAtRouteNegotiatedContentResult<User>;

            Assert.IsNull(result);
        }

        [TestMethod]
        public void PostUser_ShouldCheckInvalidEmailInUser()
        {
            var controller = new UserController(new TestStoreAppContext());

            var item = GetDemoUser();
            item.Email = "abrakadabra";

            var result =
                controller.PostUser(item) as CreatedAtRouteNegotiatedContentResult<User>;

            Assert.IsNull(result);
        }

        [TestMethod]
        public void PostUser_ShouldCheckInvalidGenderInUser()
        {
            var controller = new UserController(new TestStoreAppContext());

            var item = GetDemoUser();
            item.Gender = "RockNRoll";

            var result =
                controller.PostUser(item) as CreatedAtRouteNegotiatedContentResult<User>;

            Assert.IsNull(result);
        }

        [TestMethod]
        public void PostUser_ShouldNotSaveOnNullUser()
        {
            var controller = new UserController(new TestStoreAppContext());

            var item = GetDemoUser();
            item.Id = 0;
            item.FirstName = "";
            item.LastName = "";
            item.Email = "";
            item.Password = "";
            item.Gender = "";

            var result =
                controller.PostUser(item) as CreatedAtRouteNegotiatedContentResult<User>;

            Assert.IsNull(result);
        }

        [TestMethod]
        public void PostUser_ShouldValidatePasswordsLessThan8Chars()
        {
            var controller = new UserController(new TestStoreAppContext());
            var item = GetDemoUser();
            item.Password = "Rock";

            var result =
                controller.PostUser(item) as CreatedAtRouteNegotiatedContentResult<User>;
            Assert.IsTrue(item.Password.Length<=7);
            Assert.IsNull(result);
        }

        [TestMethod]
        public void PostUser_ShouldNotSaveWhenNull()
        {
            var controller = new UserController(new TestStoreAppContext());
            var item = GetDemoUser();
            item = null;

            var result =
                controller.PostUser(item) as CreatedAtRouteNegotiatedContentResult<User>;

            Assert.IsNull(result);
        }

        [TestMethod]
        public void PutUser_ShouldReturnStatusCode()
        {
            var controller = new UserController(new TestStoreAppContext());

            var item = GetDemoUser();

            var result = controller.PutUser(item.Id, item) as StatusCodeResult;
            Assert.IsNotNull(result);
            Assert.IsInstanceOfType(result, typeof(StatusCodeResult));
            Assert.AreEqual(HttpStatusCode.NoContent, result.StatusCode);
        }

        [TestMethod]
        public void PutUser_ShouldFail_WhenDifferentID()
        {
            var controller = new UserController(new TestStoreAppContext());

            var badresult = controller.PutUser(999, GetDemoUser());
            Assert.IsInstanceOfType(badresult, typeof(BadRequestResult));
        }

       

        [TestMethod]
        public void GetUser_ShouldReturnUserWithSameID()
        {
            var context = new TestStoreAppContext();
            context.Users.Add(GetDemoUser());

            var controller = new UserController(context);
            var result = controller.GetUser(3) as OkNegotiatedContentResult<User>;

            Assert.IsNotNull(result);
            Assert.AreEqual(3, result.Content.Id);
        }

        [TestMethod]
        public void GetUsers_ShouldReturnAllUsersWithSameModel()
        {
            var context = new TestStoreAppContext();
            context.Users.Add(GetDemoUser());
            var controller = new UserController(context);
            var result = controller.GetUser(3) as OkNegotiatedContentResult<User>;
            Assert.IsInstanceOfType(result.Content, typeof(User));
            Assert.IsNotNull(result);
        }

        [TestMethod]
        public void GetUsers_ShouldReturnAllUsers()
        {
            var context = new TestStoreAppContext();
            context.Users.Add(new User { Id = 1, FirstName = "Sam", LastName = "Micheal", Email = "sam.micheal@fault.com", Gender = "Male", Password = "sammicheal" });
            context.Users.Add(new User { Id = 2, FirstName = "Shaun", LastName = "Micheal", Email = "shaun.micheal@fault.com", Gender = "Male", Password = "shaunmicheal" });
            context.Users.Add(new User { Id = 3, FirstName = "Tess", LastName = "Micheal", Email = "tess.micheal@fault.com", Gender = "Male", Password = "tessmicheal" });

            var controller = new UserController(context);
            var result = controller.GetUsers() as TestUserDbSet;

            Assert.IsNotNull(result);
            Assert.AreEqual(3, result.Local.Count);
        }

        [TestMethod]
        public void DeleteUser_ShouldReturnOK()
        {
            var context = new TestStoreAppContext();
            var item = GetDemoUser();
            context.Users.Add(item);

            var controller = new UserController(context);
            var result = controller.DeleteUser(3) as OkNegotiatedContentResult<User>;

            Assert.IsNotNull(result);
            Assert.AreEqual(item.Id, result.Content.Id);
        }

        [TestMethod]
        public void PostUser_CheckReturnValue()
        {
            bool result = DownloadPageAsync().IsFaulted;
          
            Assert.AreEqual(true, !result);
        }

        User GetDemoUser()
        {
            return new User() { Id = 3, FirstName = "Sam",LastName="Micheal", Email = "sam.micheal@fault.com",Gender="Male",Password="sammicheal" };
        }

        /*[TestMethod]
        public void PostUser_GetUserDetails()
        {
            using (var ctx = new SessionContext())
            {
                using (var innerCtx = new SessionContext())
                {
                    var outerSession = innerCtx.Session;
                    var innerSession = innerCtx.Session;
                    Assert.AreSame(outerSession, innerSession);
                    using (var mostInnerCtx = new SessionContext(new WebIdentity()))
                    {
                        var mostInnerSession = innerCtx.Session;
                        Assert.AreNotSame(mostInnerSession, innerSession);
                    }
                }
            }
        }*/

        static async Task<bool> DownloadPageAsync()
        {
            // ... Target page.
            string page = "http://localhost:59472/api/users";

            // ... Use HttpClient.
            using (HttpClient client = new HttpClient())
            using (HttpResponseMessage response = await client.GetAsync(page))
            using (HttpContent content = response.Content)
            {
                // ... Read the string.
                string result = await content.ReadAsStringAsync();
                content.Headers.Contains("");
                // ... Display the result.
                if (result == null)
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }
        }
    }





Step 8 : Create another class "TestSimpleUserController" having code

[TestClass]
    public class TestSimpleUserController
    {
        [TestMethod]
        public void GetAllUsers_ShouldReturnAllUsers()
        {
            var testUsers = GetTestUsers();
            var controller = new SimpleUserController(testUsers);

            var result = controller.GetAllUsers() as List<User>;
            Assert.AreEqual(testUsers.Count, result.Count);
        }

        [TestMethod]
        public async Task GetAllUsersAsync_ShouldReturnAllUsers()
        {
            var testUsers = GetTestUsers();
            var controller = new SimpleUserController(testUsers);

            var result = await controller.GetAllUsersAsync() as List<User>;
            Assert.AreEqual(testUsers.Count, result.Count);
        }

        [TestMethod]
        public void GetUser_ShouldReturnCorrectUser()
        {
            var testUsers = GetTestUsers();
            var controller = new SimpleUserController(testUsers);

            var result = controller.GetUser(4) as OkNegotiatedContentResult<User>;
            Assert.IsNotNull(result);
            Assert.AreEqual(testUsers[3].FirstName, result.Content.FirstName);
            Assert.AreEqual(testUsers[3].LastName, result.Content.LastName);
            Assert.AreEqual(testUsers[3].Email, result.Content.Email);
            Assert.AreEqual(testUsers[3].Password, result.Content.Password);
            Assert.AreEqual(testUsers[3].Gender, result.Content.Gender);
        }

        [TestMethod]
        public async Task GetUserAsync_ShouldReturnCorrectUser()
        {
            var testUsers = GetTestUsers();
            var controller = new SimpleUserController(testUsers);

            var result = await controller.GetUserAsync(4) as OkNegotiatedContentResult<User>;
            Assert.IsNotNull(result);
            Assert.AreEqual(testUsers[3].FirstName, result.Content.FirstName);
            Assert.AreEqual(testUsers[3].LastName, result.Content.LastName);
            Assert.AreEqual(testUsers[3].Email, result.Content.Email);
            Assert.AreEqual(testUsers[3].Password, result.Content.Password);
            Assert.AreEqual(testUsers[3].Gender, result.Content.Gender);
        }

        [TestMethod]
        public void GetUser_ShouldNotFindUser()
        {
            var controller = new SimpleUserController(GetTestUsers());

            var result = controller.GetUser(999);
            Assert.IsInstanceOfType(result, typeof(NotFoundResult));
        }

        private List<User> GetTestUsers()
        {
            var testUsers = new List<User>();
            testUsers.Add(new User { Id = 1, FirstName = "Sam", LastName = "Micheal", Email = "sam.micheal@fault.com", Gender = "Male", Password = "sammicheal" });
            testUsers.Add(new User { Id = 2, FirstName = "Shaun", LastName = "Micheal", Email = "shaun.micheal@fault.com", Gender = "Male", Password = "shaunmicheal" });
            testUsers.Add(new User { Id = 3, FirstName = "Tess", LastName = "Micheal", Email = "tess.micheal@fault.com", Gender = "Male", Password = "tessmicheal" });
            testUsers.Add(new User { Id = 4, FirstName = "Alex", LastName = "Micheal", Email = "alex.micheal@fault.com", Gender = "Male", Password = "alexmicheal" });
            testUsers.Add(new User { Id = 5, FirstName = "John", LastName = "Micheal", Email = "john.micheal@fault.com", Gender = "Male", Password = "johnmicheal" });
            return testUsers;
        }
    }

Step 8 : Create user db set class with name "TestUserDbSet" with code

class TestUserDbSet : TestDbSet<User>
    {
        public override User Find(params object[] keyValues)
        {
            return this.SingleOrDefault(user => user.Id == (int)keyValues.Single());
        }
    }

Step 9 : Build and compile your solution, Set the test project as start up page and from "Run" menu run the tests. The fault injections will inject the values which will be checked by the unit test to verify wether the service has a bug against injecting the faults.

Thanks
Ritesh Tandon

No comments:

Post a Comment

Comments are welcome, Please join me on my Linked In account

http://in.linkedin.com/pub/ritesh-tandon/21/644/33b

How to implement Captcha v3 in ASP.NET

 I was facing an issue of dom parsing in my website. I finally resolved it by using Google Captcha V3. Step 1: Get your keys from https:...