首页 > 解决方案 > 单元测试 + 工作单元 + 存储库

问题描述

我不得不寻求帮助。我正在写博客。架构是这样的,有 IRepository、PostRepository 和 Unit OfWork。我刚开始熟悉单元测试,无法理解如何正确测试方法。我非常希望您帮助创建一个测试 - 返回博客中所有帖子的列表,其余的我将自己完成。以下是清单:

后控制器:

using namespace WebSite.Controllers
{
public class PostsController : Controller
{
    readonly UnitOfWork unitOfWork;

    public ActionResult Index()
    {
        var postList = unitOfWork.Post.GetList();
        return View( postList );
    }


    public ActionResult Details( int? id )
    {
        if (id == null)
        {
            return new HttpStatusCodeResult( HttpStatusCode.BadRequest );
        }
        var post = unitOfWork.Post.Get( id );
        if (post == null)
        {
            return HttpNotFound();
        }
        return View( post );
    }

    public ActionResult Create()
    {
        return View();
    }


    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create(
        [Bind( Include = 
"Id,Title,Description,Content,Category,PostedDateTime,ModifiedDateTime" )] 
Post post, HttpPostedFileBase file )
    {

        post.Author = User.Identity.Name;
        if (!ModelState.IsValid || file == null)
            return View( post );
        //attach the uploaded image to the object before saving to Database
        post.ImageMimeType = "image / jpeg" /*image.ContentLength*/;
        post.ImageData = new byte[file.ContentLength];
        file.InputStream.Read( post.ImageData, 0, file.ContentLength );

        //Save image to file
        var filename = file.FileName;
        var filePathOriginal = Server.MapPath( "~/Images/Original" );
        var savedFileName = Path.Combine( filePathOriginal, filename );
        file.SaveAs( savedFileName );

        //Read image back from file and create thumbnail from it
        var imageFile = Path.Combine( Server.MapPath( "~/Images/Original" ), 
filename );
        using (var srcImage = Image.FromFile( imageFile ))
        using (var newImage = new Bitmap( 100, 100 ))
        using (var graphics = Graphics.FromImage( newImage ))
        using (var stream = new MemoryStream())
        {
            graphics.SmoothingMode = SmoothingMode.AntiAlias;
            graphics.InterpolationMode = 
InterpolationMode.HighQualityBicubic;
            graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
            graphics.DrawImage( srcImage, new Rectangle( 0, 0, 100, 100 ) );
            newImage.Save( stream, ImageFormat.Png );
            var thumbNew = File( stream.ToArray(), "image/png" );
            post.ImageThumbnail = thumbNew.FileContents;
        }
        post.PostedDateTime = DateTime.Now;
        unitOfWork.Post.Create( post );
        unitOfWork.Save();
        return RedirectToAction( "Index", "Home" );
    }

    [HttpGet]
    public ActionResult Edit( int? id )
    {
        if (id == null)
        {
            return new HttpStatusCodeResult( HttpStatusCode.BadRequest );
        }
        var post = unitOfWork.Post.Get( id );
        if (post == null)
        {
            return HttpNotFound();
        }
        return View( post );
    }


    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit(
         Post post, 
 HttpPostedFileBase file )
    {
        if (!ModelState.IsValid)
            return View( post );
        if (file != null)
        {
            //attach the uploaded image to the object before saving to 
Database
            post.ImageMimeType = "image / jpeg" /*image.ContentLength*/;
            post.ImageData = new byte[file.ContentLength];
            file.InputStream.Read( post.ImageData, 0, file.ContentLength );

            //Save image to file
            var filename = file.FileName;
            var filePathOriginal = Server.MapPath( "~/Images/Original" );
            var savedFileName = Path.Combine( filePathOriginal, filename );
            file.SaveAs( savedFileName );

            //Read image back from file and create thumbnail from it
            var imageFile = Path.Combine( Server.MapPath( 
 "~/Images/Original" ), filename );
            using (var srcImage = Image.FromFile( imageFile ))
            using (var newImage = new Bitmap( 350, 200 ))
            using (var graphics = Graphics.FromImage( newImage ))
            using (var stream = new MemoryStream())
            {
                graphics.SmoothingMode = SmoothingMode.AntiAlias;
                graphics.InterpolationMode = 
InterpolationMode.HighQualityBicubic;
                graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
                graphics.DrawImage( srcImage, new Rectangle( 0, 0, 350, 200 
) );
                newImage.Save( stream, ImageFormat.Png );
                var thumbNew = File( stream.ToArray(), "image/png" );
                post.ImageThumbnail = thumbNew.FileContents;
            }
        }
        unitOfWork.Post.Edit( post );
        unitOfWork.Save();
        return RedirectToAction( "Index", "Home" );
    }

    public ActionResult Delete( int? id )
    {
        if (id == null)
        {
            return new HttpStatusCodeResult( HttpStatusCode.BadRequest );
        }
        var post = unitOfWork.Post.Get( id );
        if (post == null)
        {
            return HttpNotFound();
        }
        return View( post );
    }

    [HttpPost, ActionName( "Delete" )]
    [ValidateAntiForgeryToken]
    public ActionResult DeleteConfirmed( int id )
    {
        {
            var post = unitOfWork.Post.Get( id );
            unitOfWork.Post.Delete( post );
            unitOfWork.Save();
            return RedirectToAction( "Index" );
        }
    }
    public FileContentResult GetThumbnailImage( int? id )
    {
        var post = unitOfWork.Post.Get( id );
        if (post.ImageThumbnail != null)
        {
            return File( post.ImageThumbnail, post.ImageMimeType );
        }
        else if (post.ImageThumbnail == null && post.ImageData == null)
        {
            var imageFile = Path.Combine( Server.MapPath( 
 "~/Images/Original/NoImageAvailable.jpg" ) );
            post.ImageMimeType = "image / jpeg";
            using (var srcImage = Image.FromFile( imageFile ))
            using (var newImage = new Bitmap( 350, 200 ))
            using (var graphics = Graphics.FromImage( newImage ))
            using (var stream = new MemoryStream())
            {
                graphics.SmoothingMode = SmoothingMode.AntiAlias;
                graphics.InterpolationMode = 
InterpolationMode.HighQualityBicubic;
                graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
                graphics.DrawImage( srcImage, new Rectangle( 0, 0, 350, 200 
) );
                newImage.Save( stream, ImageFormat.Png );
                var thumbNew = File( stream.ToArray(), "image/png" );
                post.ImageThumbnail = thumbNew.FileContents;
            }
            return File( post.ImageThumbnail, post.ImageMimeType );
        }
        else 
        {
            var imageFile = Path.Combine( Server.MapPath( "~/Images/Default" 
 ), post.DefaultImageName );
            using (var srcImage = Image.FromFile( imageFile ))
            using (var newImage = new Bitmap( 350, 200 ))
            using (var graphics = Graphics.FromImage( newImage ))
            using (var stream = new MemoryStream())
            {
                graphics.SmoothingMode = SmoothingMode.AntiAlias;
                graphics.InterpolationMode = 
 InterpolationMode.HighQualityBicubic;
                graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
                graphics.DrawImage( srcImage, new Rectangle( 0, 0, 350, 200 
 ) );
                newImage.Save( stream, ImageFormat.Png );
                var thumbNew = File( stream.ToArray(), "image/png" );
                post.ImageThumbnail = thumbNew.FileContents;
            }
            return File( post.ImageThumbnail, post.ImageMimeType );
        }
    }
    public ActionResult ChangeStatus( int id )
    {
        var post = unitOfWork.Post.Get( id );
        if (post != null && post.IsDeclined || post != null && 
 !post.IsApproved)
        {
            post.IsDeclined = false;
            post.IsApproved = true;
        }
        else if (post != null && post.IsApproved || post !=null && 
 !post.IsDeclined)
        {
            post.IsApproved = false;
            post.IsDeclined = true;
        }
        unitOfWork.Post.Edit( post );
        unitOfWork.Save();
        return RedirectToAction( "Index","Home" );
    }
  }
}

后存储库:

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using Common.App_Data;
using Common.Models;

namespace Common.Services.Repositories
{
public class PostRepository : IRepository<Post>, IDisposable
{
    private BlogContext db;

    public PostRepository( BlogContext context)
    {
        db = context;
    }


    public IEnumerable<Post> GetList()
    {
        return db.Posts.ToList();
    }

    public Post Get(int? id)
    {
        return db.Posts.Find( id );
    }

    public void Create( Post post ) // create object--Action : Posts/Create
    {
        post.PostedDateTime = DateTime.Now;
        db.Posts.Add( post );
    }

    public void Delete( Post post ) // delete object --Action : Posts/Delete 
    {
        if (post == null) return;
        db.Posts.Remove(post);
    }

    public void Edit( Post post ) // edit object--Action : Posts/Edit
    {
        post.ModifiedDateTime = DateTime.Now;
        db.Entry( post ).State = EntityState.Modified;
    }

   private bool disposed = false;
    public virtual void Dispose( bool disposing )
    {
        if (!disposed)
        {
            if (disposing)
            {
                db.Dispose();
            }
            disposed = true;
        }
    }
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize( this );
    }


 }
}

存储库

using System.Collections.Generic;

namespace Common.Services.Repositories
{
public interface IRepository<T> where T : class
{
    IEnumerable<T> GetList();
    T Get(int? id); 
    void Create(T item); 
    void Edit(T item);
    void Delete( T item ); 

}
}

工作单位:

using System;
using System.Data.Entity.Validation;
using System.Linq;
using Common.App_Data;

namespace Common.Services.Repositories
{
 public class UnitOfWork : IDisposable
{
    private BlogContext db;
    private PostRepository postRepository;


    public UnitOfWork(BlogContext mockdb, PostRepository mockpostRepository)
    {
        db = mockdb;
        postRepository = mockpostRepository;
    }

    public PostRepository Post => postRepository ?? (postRepository = new 
 PostRepository( db ));

    public void Save()
    {
        try
        {
            db.SaveChanges();
        }
        catch (DbEntityValidationException dbEx)
        {
            var raise = 
    dbEx.EntityValidationErrors.Aggregate<DbEntityValidationResult, 
 Exception>(dbEx, (current1, validationErrors) => 
            validationErrors.ValidationErrors.Select(validationError =>
            $"{validationErrors.Entry.Entity.ToString()}: 
 {validationError.ErrorMessage}").Aggregate(current1, (current, message) => 
            new InvalidOperationException(message, current)));
            throw raise;
        }
    }

    private bool disposed = false;

   public virtual void Dispose( bool disposing )
    {
        if (disposed) return;
        if (disposing)
        {
            db.Dispose();
        }
        disposed = true;
    }

    public void Dispose()
    {
        Dispose( true );
        GC.SuppressFinalize( this );
    }
  }
    }

    private bool disposed = false;

   public virtual void Dispose( bool disposing )
    {
        if (disposed) return;
        if (disposing)
        {
            db.Dispose();
        }
        disposed = true;
    }

    public void Dispose()
    {
        Dispose( true );
        GC.SuppressFinalize( this );
    }
  }
}

好吧,其实在第一次测试的时候,我想抗议一下,执行GetList()方法的时候,返回的是posts列表(是的,一般情况下——或者结果不为零),我大概需要使用mocks在这里,但我开始对它们感到困惑,越简单越好。测试未通过((

测试尝试#1

using Common.Services.Repositories;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace UnitTests.Test
{
[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void GetListOfPostsReturnsNotNull()
    {
        //Arrange
        var unitOfWork = new UnitOfWork();
        //Act
        var testList = unitOfWork.Post.GetList();
        //Asset
        Assert.IsNotNull(testList);
    }
 }
}

测试尝试#2

[TestMethod]
    public void GetListOfPostsReturnsNotNull()
    {
        //Arrange
        var mockDb = new Mock<BlogContext>();
        var mockRep = new Mock<PostRepository>();
        var unitOfWork = new UnitOfWork(mockDb.Object,mockRep.Object);

        //Act
        var testList = unitOfWork.Post.GetList();
        //Asset
        Assert.IsNotNull(testList);
    }

标签: unit-testingunit-of-work

解决方案


  public void GetListOfPostsReturnsNotNull()
    {
        mockDb = new Mock<BlogContext>();
        mockRep = new Mock<IRepository<Post>>();
        mockUnitOfWork = new Mock<UnitOfWork>(mockDb,mockRep);

        //Arrange

        var posts = new List<Post>()
        {
            new Post
            {
                Id = 1,
                Title = "Amazon",
                Description = "Amazon daily deals for Tuesday, April 17",
                Category = "Technology",
                Content =
                    "If you\'re looking to add a little extra...",
                Author = "blogger123@com.com",
            },
            new Post
            {
                Id = 2,
                Title = "Ford",
                Description = "Ford charges into electric bike-sharing",
                Category = "Technology",
                Content =  "I got to try one out...",
                Author = "blogger123@com.com",
            }
        };

        mockUnitOfWork.Setup(x => x.Post.GetList()).Returns(posts); \\ ERROR
        //Act
        var testList = mockUnitOfWork.Object.Post.GetList();
        //Asset
        Assert.IsNotNull(testList);
    }
}
}

推荐阅读