This article provides insights on how one would consider integrating a 3rd Party SDK to extend and use within the context of the MicroStation CONNECT SDK. This article will show the necessary steps to integrate the popular GoogleTest Framework and access some basic features.
As your custom applications become larger and more complex with accelerated release schedules you will want to apply more software industry best practices like Unit Testing and Automated Testing to your software application build processes. To keep this article brief, it will not attempt to discuss or address these fundamental and important topics for which there are numerous resources available a reader can explore. So, let’s get started with the stepwise instructions…
Make sure to perform each step in the order presented to ensure proper setup.
The following diagram illustrates how a typical MDL application (dark blue) interacts with MicroStation and how a GTest enabled MDL application (light blue) with Tests interact with MicroStation DLLs:
1. Writing Test Fixture (Used when required Same Data Configuration for Multiple Tests):
class AccudrawDemoTest : public testing::Test { private: static bool m_isFileOpened; DgnModelRefP m_modelRef; DPoint3d m_startPoint; DPoint3d m_endPoint; bool m_doVerifyEndPoints; bool m_doVerifyOnlyStartPoint; public: virtual void SetUp() override; virtual void TearDown() override; void DoLineVerification(DgnModelRefP& modelRef, ICurvePrimitivePtr& pathMember); void DoLineVerification(DgnModelRefP& modelRef, ElementId id); static void VerifyAppIsLoaded(bool shouldBeLoaded, WCharCP modelname); };
2. SetUp and TearDown Methods:
Void FooTest::SetUp() { WString testData(L”C:\TestDAta\seed3d.dgn”); if (0 != ::CopyFileW(testData.c_str(), tempFile.c_str(), false)) { if (SUCCESS != mdlSystem_newDesignFile(tempFile.c_str())) { FAIL() << "MDL method mdlSystem_newDesignFile() failed to load the file. Aborting this test here..."; } else { m_dgnFile = ISessionMgr::GetActiveDgnFile(); ASSERT_TRUE(NULL != m_dgnFile); } } else { FAIL() << "Unable to make a copy of test file and initialize"; } WCharCP modelname = L"adrwdemo"; mdlInput_sendSynchronizedKeyin(L"MDL LOAD adrwdemo", 0, INPUTQ_EOQ, NULL); VerifyAppIsLoaded(true, modelname); modelname = L"ModelExample"; mdlInput_sendSynchronizedKeyin(L"MDL LOAD ModelExample", 0, INPUTQ_EOQ, NULL); }
void AccudrawDemoTest::SetUp() { AccudrawDemoTest::m_isFileOpened = false; AccudrawDemoTest::m_isFileOpened = true; DgnFileP dgnFile = ISessionMgr::GetActiveDgnFile(); ASSERT_TRUE(NULL != dgnFile); m_modelRef = mdlModelRef_getActive(); ASSERT_TRUE(NULL != m_modelRef); WCharCP modelname = L"adrwdemo"; mdlInput_sendSynchronizedKeyin(L"MDL LOAD adrwdemo", 0, INPUTQ_EOQ, NULL); VerifyAppIsLoaded(true, modelname); modelname = L"ModelExample"; mdlInput_sendSynchronizedKeyin(L"MDL LOAD ModelExample", 0, INPUTQ_EOQ, NULL); VerifyAppIsLoaded(true, modelname); }
void AccudrawDemoTest::TearDown() { WCharCP modelname = L"adrwdemo"; mdlInput_sendSynchronizedKeyin(L"MDL UNLOAD adrwdemo", 0, INPUTQ_EOQ, NULL); modelname = L"ModelExample"; mdlInput_sendSynchronizedKeyin(L"MDL UNLOAD ModelExample", 0, INPUTQ_EOQ, NULL); //Verify example is unloaded. VerifyAppIsLoaded(false, modelname); if (AccudrawDemoTest::m_isFileOpened) { mdlSystem_saveDesignFile(); } }
3. Some useful Methods in gtest.h:
4. Example for using Fixture:
TEST_F(AccudrawDemoTest, Create3dDesign) { mdlInput_sendSynchronizedKeyin(L"MODELEXAMPLE CREATE 3DDESIGN Test_3DesignModel", 0, INPUTQ_EOQ, NULL); DoValidateModel(L"Test_3DesignModel"); } /*---------------------------------------------------------------------------------**//** +---------------+---------------+---------------+---------------+---------------+------*/ TEST_F(AccudrawDemoTest, Create2Design) { mdlInput_sendSynchronizedKeyin(L"MODELEXAMPLE CREATE 2DDESIGN Test_2DesignModel", 0, INPUTQ_EOQ, NULL); DoValidateModel(L"Test_2DesignModel"); }
5. Writing Run Function:
extern "C" __declspec(dllexport) int Run (int argc, WCharCP argv) { WCharCP * m_argv = &argv; ::testing::InitGoogleTest(&argc,(wchar_t **)m_argv); int status = RUN_ALL_TESTS(); return status; }
6. Validating Test Results:
void AccudrawDemoTest::DoLineVerification(DgnModelRefP& modelRef, ICurvePrimitivePtr& pathMember) { DSegment3d segment = *pathMember->GetLineCP(); //Verify end points. if (m_doVerifyEndPoints) { CheckDPoint3dForEquality(AccudrawDemoTest::m_startPoint, segment.point[0]); if (!AccudrawDemoTest::m_doVerifyOnlyStartPoint) CheckDPoint3dForEquality(AccudrawDemoTest::m_endPoint, segment.point[1]); } printf("length of Drwan line is %f \n", segment.Length()); } /*---------------------------------------------------------------------------------**//** +---------------+---------------+---------------+---------------+---------------+------*/ void AccudrawDemoTest::DoLineVerification(DgnModelRefP& modelRef, ElementId id) { PersistentElementRefP pElemRef; DgnModelP model = mdlModelRef_getDgnModel(modelRef); pElemRef = model->FindElementByID(id); EXPECT_TRUE(NULL != pElemRef); EditElementHandle elem(pElemRef, modelRef); ASSERT_TRUE(elem.IsValid()); //Element Type: We know this is a line. ASSERT_EQ(&LineHandler::GetInstance(), &elem.GetHandler()); //Element Geometric properties. We know this is a line element. CurveVectorPtr pathCurve = ICurvePathQuery::ElementToCurveVector(elem); ASSERT_TRUE(pathCurve.IsValid()); ICurvePrimitivePtr& pathMember = pathCurve->front(); ASSERT_TRUE(pathMember.IsValid()); ASSERT_TRUE(ICurvePrimitive::CURVE_PRIMITIVE_TYPE_Line == pathCurve->HasSingleCurvePrimitive()); DoLineVerification(modelRef, pathMember); }
7. All unit tests are written we need Runner to Run those tests in MicroStation.
static void Adrwtestrunner_runtest(WCharCP unparsed) { int testResult = 0; RunTestsImport runTestsFunc; HINSTANCE hinstLib; WString pathname(getenv("OutRoot")); if (pathname == WString("")) { hinstLib = LoadLibraryW(L"AccudrawDemoTest.dll"); if (0 == hinstLib) { printf("ERROR: Unable to load AccudrawDemoTest.dll"); return; } } }
runTestsFunc = (RunTestsImport)GetProcAddress(hinstLib, "Run"); testResult = runTestsFunc(GTestRunner::m_argc, GTestRunner::m_argv1); FreeLibrary(hinstLib);
We hope you find this information useful and value your feedback. Please feel free to share any feedback or questions you have on the MicroStation SDK communities