Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/256.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
单元测试混合C++;/Visual Studio中的CLI/C#代码失败_C#_C++_Visual Studio_Unit Testing_C++ Cli - Fatal编程技术网

单元测试混合C++;/Visual Studio中的CLI/C#代码失败

单元测试混合C++;/Visual Studio中的CLI/C#代码失败,c#,c++,visual-studio,unit-testing,c++-cli,C#,C++,Visual Studio,Unit Testing,C++ Cli,我们得到了一个C#DLL,其中包含加载和操作专有数据格式所需的代码。我们的代码库主要是原生C++。为了能够访问提供的库,我编写了一个DLL,其中包括 实现必要的API 的本地C++包装器类 一个C++/CLI桥接类,用于封送数据进出,并将调用委托给C#DLL 我编写了一个基本的(原生)C++控制台应用程序,测试API是否符合我的需要。是的。然后,我编写了一个(本地的,MicrosoftVisualStudio)单元测试项目来调用API。令人惊讶的是,在构造接口对象时,它会崩溃,并出现一些未声

我们得到了一个C#DLL,其中包含加载和操作专有数据格式所需的代码。我们的代码库主要是原生C++。为了能够访问提供的库,我编写了一个DLL,其中包括

  • 实现必要的API
  • 的本地C++包装器类
  • 一个C++/CLI桥接类,用于封送数据进出,并将调用委托给C#DLL

我编写了一个基本的(原生)C++控制台应用程序,测试API是否符合我的需要。是的。然后,我编写了一个(本地的,MicrosoftVisualStudio)单元测试项目来调用API。令人惊讶的是,在构造接口对象时,它会崩溃,并出现一些未声明的异常

一些最小代码:

PAPI.h:

#pragma once
#pragma unmanaged

#if defined(INTEROP_API_EXPORTS)
#define INTEROP_API __declspec(dllexport)
#else
#define INTEROP_API __declspec(dllimport)
#endif

#include <string>

class InteropBridgeArchive;

struct InteropRecord
{
    std::string Name;
    int Id;
    std::string Data;
};

class INTEROP_API InteropAPI
{
public:
    InteropAPI();
    ~InteropAPI();

    InteropRecord GetRecord(int id) const;

private:
    InteropBridgeArchive * impl_;
};
内桥

#pragma once
#pragma unmanaged
#include "InteropAPI.h"

#pragma managed

#include <vcclr.h>

class InteropBridge
{
public:
    InteropArchive();
    InteropRecord GetRecord(System::Int32 id) const;

private:
    gcroot<InteropCSharpDll::Archive^> archive_;
};
显然,如果这种混合结构不能作为本机代码进行单元测试,我们就无法测试任何涉及它的内容,因此弄清它崩溃的原因是非常重要的。这个代码运行得很好,作为一个本地C++项目:

#include <cstdio>
#include <iostream>
#include "../InteropCppCliBridgeDll/InteropAPI.h"

#pragma comment(lib, "../x64/Debug/InteropCppCliBridgeDll.lib")

int main(int , char ** )
{
    const InteropAPI archive;
    const auto record = archive.GetRecord(0);
    std::cout << "Name: " << record.Name << "\n";
    std::cout << "Id: " << record.Id<< "\n";
    std::cout << "Data: " << record.Data<< "\n\n";
}

托管代码喜欢抛出异常,当未捕获异常并将其转换为本机代码时,您会像蝙蝠一样盲目。使用项目>属性>调试>调试类型进行调试=混合。启用本机和托管调试引擎后,您现在也可以看到托管异常。调试>窗口>异常设置并勾选“公共语言运行时异常”,以便在引发异常时调试器中断。在可识别代码中不一定存在FileNotFoundException,当抖动无法在执行之前编译代码时,FileNotFoundException非常常见。这有点帮助:我现在看到多个异常:第一个是System.BadImageFormatException:'无法加载文件或程序集'Microsoft.VisualStudio.Coverage.Interop'或其依赖项之一。试图加载格式不正确的程序。然后System.IO.FileNotFoundException:“无法加载文件或程序集”BoostTestAdapter.XmlSerializers。。。System.IO.FileNotFoundException:“无法加载文件或程序集”GoogleTestAdapter.XmlSerializers。。。XmlSerializer异常是正常的,就XML序列化的实现方式而言,BadImageFormat是您的敌人。我不会冒险去猜测这是怎么出错的。VisualStudio的Google Test runner似乎没有遇到这个问题,所以我把我的测试转移到了那个问题上。这不是一个很好的解决方案,因为我们的大部分测试代码都是MSTEST。不过,总比什么都没有好。哦,我已经向微软报告了这个问题。
#pragma unmanaged
#include <string>
#pragma managed
#include "InteropBridge.h"
#include <msclr/marshal_cppstd.h>

InteropBridge::InteropBridge()
{
    archive_ = gcnew InteropCSharpDll::Archive;
}

InteropRecord InteropBridge::GetRecord(const System::Int32 id) const
{
    auto return_value = archive_->GetRecord(id);
    InteropRecord record;
    record.Name = msclr::interop::marshal_as<std::string>(return_value.Name);
    record.Id = return_value.Id;
    record.Data = msclr::interop::marshal_as<std::string>(return_value.Data);
    return record;
}
using System.Linq;

namespace InteropCSharpDll
{
    public struct Record
    {
        public string Name;
        public int Id;
        public string Data;
    }

    public class Archive
    {
        public Record GetRecord(int id)
        {
            return _records.First(r => r.Id == id);
        }

        private readonly Record[] _records = 
        {
            new Record {Name = "Foo", Id = 0, Data = "Foo.Data"},
            new Record {Name = "Bar", Id = 2, Data = "Bar.Data"},
            new Record {Name = "Egg", Id = 7, Data = "Egg.Data"},
        };
    }
}
#include <cstdio>
#include <iostream>
#include "../InteropCppCliBridgeDll/InteropAPI.h"

#pragma comment(lib, "../x64/Debug/InteropCppCliBridgeDll.lib")

int main(int , char ** )
{
    const InteropAPI archive;
    const auto record = archive.GetRecord(0);
    std::cout << "Name: " << record.Name << "\n";
    std::cout << "Id: " << record.Id<< "\n";
    std::cout << "Data: " << record.Data<< "\n\n";
}
archive_ = gcnew InteropCSharpDll::Archive;