简体   繁体   English

访问实体数据库的单元测试功能

[英]Unit testing functions which access Entity Database

Trying to unit test functions which access a entity framework. 尝试对访问实体框架的功能进行单元测试。 So i tried to put all the entity code into the test function below? 所以我试图将所有实体代码放入下面的测试函数中? However it stops at the Linq statement; 但是,它止于Linq语句; obviously trying to access the database is too much drama for it. 显然,尝试访问数据库实在太麻烦了。 Maybe a work around would be too to create a replica database within the unit test function based on sql lite or compact;(Its not a big database anyways) then execution would not have to leave the test function? 也许也可以在基于sql lite或compact的单元测试函数中创建一个副本数据库;(无论如何它不是一个大数据库),然后执行就不必离开测试函数了吗? Is this possible and how would i implement it? 这可能吗,我将如何实施?

public void RetreiveKeyFnTest()
    {
        StegApp target = new StegApp(); // TODO: Initialize to an appropriate value
        string username = "david"; // TODO: Initialize to an appropriate value
        string password = "david1"; // TODO: Initialize to an appropriate value
        string ConnectionString = ConfigurationManager.ConnectionStrings["DatabaseEntities"].ToString();
        var dataContext = new DatabaseEntities(ConnectionString);
        var user = dataContext.Users.FirstOrDefault(u => u.Username.Equals(username) && u.Password.Equals(password));
        Assert.IsNotNull(user);

        //target.RetreiveKeyFn(username, password);
        //Assert.IsInstanceOfType(target.RetreiveLogs,typeof(DataAccess));
        //Assert.IsInstanceOfType(target.p);
        //Assert.IsNotNull(target.RetreiveLogs.AuthenitcateCredentials(username,password));
        //Assert.Inconclusive("A method that does not return a value cannot be verified.");
    }

Below is the code i am trying to test: 以下是我要测试的代码:

public void RetreiveKeyFn(string username, string password)
    {

        BusinessObjects.User p = RetreiveLogs.AuthenitcateCredentials(username,password);
        if (p != null)
        {
            if (RetreiveLogs.RetreiveMessages(p.UserId) == null)
            {
                DisplayLogs.Text = "Sorry No messages for you recorded in Database, your correspondant might have chose not to record the entry";
            }
            else
            {
                MessageBox.Show("LogId = " + RetreiveLogs.RetreiveMessages(p.UserId).LogId + "\n" +
                "UserId = " + RetreiveLogs.RetreiveMessages(p.UserId).UserId + "\n" +
                "Message Key = " + RetreiveLogs.RetreiveMessages(p.UserId).MessageKey + "\n" + "PictureId = " + RetreiveLogs.RetreiveMessages(p.UserId).PictureId +
                " Date & time = " + RetreiveLogs.RetreiveMessages(p.UserId).SentDateTime);
                DisplayLogs.Visible = true;
            }
        }
        else
        {
            MessageBox.Show("Please enter your correct username and password in order to retreive either key, image or both from Databse");
        }


    }

First, you should be able to access the same database in your test application as the one you're using in your main/actual application. 首先,您应该能够在测试应用程序中访问与在主/实际应用程序中使用的数据库相同的数据库。 You just need to make sure that your Test project contains your connection string in its own App.config. 您只需要确保您的Test项目在其自己的App.config中包含您的连接字符串即可。

The initialization of the context should be done either inside your StegApp(), or you should be able to pass a context to your StegApp() from a different scope. 上下文的初始化应该 StegApp() 内部完成,或者应该能够从其他范围将上下文传递到StegApp()。 From what I read of your code, your StegApp() will not be able to access the dataContext variable you created. 根据我对代码的了解,您的StegApp()将无法访问您创建的dataContext变量。

Your test for null user already happens inside the RetrieveKeyFn() under the AuthenticateCredentials() method so there's no need for the first "Assert.IsNotNull(user)". 对空用户的测试已经在AuthenticateCredentials()方法下的RetrieveKeyFn()内部进行,因此不需要第一个“ Assert.IsNotNull(user)”。 I would recommend separating your business logic for RetrieveKeyFn from your UI behaviors so that you can easily do unit tests. 我建议您将RetrieveKeyFn的业务逻辑与UI行为分开,以便您可以轻松进行单元测试。 You can bind the "Messagebox" operations to say a button click event handler which calls just RetrieveKeyFn(). 您可以将“ Messagebox”操作绑定为一个仅单击RetrieveKeyFn()的按钮单击事件处理程序。 I would suggest maybe something like this: 我建议也许是这样的:

public class StegApp
{

      public DatabaseEntities context;
      //other properties

      public StegApp()
      {
           //assuming your DatabaseEntities class inherits from DbContext. 
           //You should create other constructors that allow you to set options
           //like lazy loading and mappings
           this.context = new DatabaseEntities(); 
      } 

      //ASSUMING YOUR RetrieveLogs.RetrieveMessages() function returns 
      //a Message object. replace this type with whatever type the
      //RetrieveLogs.RetrieveMessages() method returns.
      public Message RetrieveKeyFn (string username, string password)
      {

          BusinessObjects.User p = RetreiveLogs.AuthenitcateCredentials(username,password);
          if (p != null)
          {
              var message = RetrieveLogs.RetrieveMessages(p.UserId);
              if (message == null)
                  // handle behavior for no messages. In this case 
                  // I will just create a new Message object with a -1 LogId
                  return new Message {LogId =-1};
              else
                  return message;
          }
          else
              //handle behavior when the user is not authenticated. 
              //In this case I throw an exception
              throw new Exception();

      }

     //on your button click handler, do something like:
     // try 
     // {
     //     var message = RetrieveKeyFn(txtUsername.Text.Trim(), txtPassword.Text.Trim());
     //     if (message.LogId == -1)
     //         DisplayLogs.Text = "Sorry No messages for you recorded in Database, your correspondant might have chose not to record the entry";
     //     else
     //     {
     //         MessageBox.Show("Log Id = " + message.LogId)
     //         etc. etc. etc.
     //     }
     // }
     // catch
     // {
     //       MessageBox.Show ("user is not authenticated");
     // }

}

When you do your unit test, remember to have the appropriate configuration strings in your test project's App.Config If the app.config does not yet exist, go ahead and create one. 进行单元测试时, 请记住在测试项目的App.Config中具有适当的配置字符串。如果app.config尚不存在,请继续创建一个。 You should create tests for all possibilities (ie 1) user is valid, you get the message, 2) user is valid, there are no messages, 3) user is invalid). 您应该为所有可能性创建测试(即1)用户有效,您收到消息,2)用户有效,没有消息,3)用户无效)。

Here's an example for case 2 这是案例2的示例

    [TestMethod]
    public void RetrieveKeyFnTest1()
    {
        StegApp target = new StegApp(); // this creates your context. I'm assuming it also creates your RetrieveLogs object, etc
        var username = "UserWithNotMessages"; //this user should exist in your database but should not have any messages. You could insert this user as part of your TestInitialize method
        var password = "UserWithNotMessagesPassword"; //this should be the proper password
        var message = target.RetrieveKeyFn(username, password);
        Assert.AreEqual (-1, message.LogId);
    }

I got my unit tests to work fine. 我的单元测试工作正常。 The mistake i had was not to copy the app.config file into the test project! 我的错误是没有将app.config文件复制到测试项目中! Although to be honest i expected Visual studio would have done that anyways. 虽然说实话,我还是希望Visual Studio能够做到这一点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM