10 Ways to Make Your Code More Testable

美女运维:你们 JAVA 服务怎么又又又又出问题了!内存降不下来!真的是空有五官没有三观! 上次520的时候公司运维美女友好的和我沟通之后,还消停没几天,今天又来找(问候)我了…… 运维:这个服务也是你们的吧,你看这个 JAVA 进程,内存占用都快 3 个 G 了,这机器才 4G,你们堆才配置 2G,都要告警了!这次是真的内存泄露了吧,不是我无知了吧! 又来搞事情……这美女是对我有意见吗?有了上次的经验,这回更自信了。还是按照惯例,先怼回去 我:“不可能,我们服务非常稳定,不会有这种问题!” 运维:你这哪来的自信和勇气?梁静茹给的吗?你先回去查查再装 看来美女这回是有备而来啊,难道真 阅读详情

Introduction
You know you have to write unit tests. You have the tools, and your team is committed to the idea. Somehow, though, despite your best intentions, the tests just never get written. Or you write them, but never run them. They always fail anyway. For one reason or another, your project is resisting the will of the unit test. Usually, this means that your code needs a good solid refactoring, to make it more accepting of the way of the test.

 
Many people have observed that unit testing fits the mold of Heisenberg’s Uncertainty Principle which says, among other things, that at the quantum level, the act of observing an event changes the nature of that event. Unit tests often have the same effect, but it extends beyond the runtime event being tested. It affects the design of the code that is to be tested, as well.

In this column, we’ll examine ten different ways you can change your code to make it ready to be tested. By doing so, you will be creating a more loosely coupled, flexible and transparent architecture, which will benefit you not only in testing but in documentation, maintenance and, eventually, modification. With a little forethought and some careful implementation, the unit tests can drive more than the QA process; it can help you design a more robust application in the first place.

Use Interfaces
Those of us who came through the COM days with our registries intact remember that most strident of admonitions: “it’s the interfaces, stupid”. To write COM code, you had to employ interfaces as the primary coupling mechanism. For the un- (or under-)initiated, interfaces are lightweight constructs which define the publicly accessible method signatures exposed by a class; they contain no implementation details whatsoever. Instantiated objects can be referred to by references of the interface type, but the interface can never be instantiated itself.

Here is a simple interface example: we’ll define an interface for interacting with different kinds of agents. The interface is called IAgent:

public interface IAgent
{
 string AgentName {get; set;}
 bool accomplishMission(TimeSpan timeLimit);
}

Agents all have a name, and can attempt to accomplish a mission in a given amount of time.

We’ll implement two different kinds of agents, SecretAgents and AirlineAgents. Airline agents perform their mission by getting people on planes, and secret agents have clandestine rendezvous’s. In addition, the SecretAgent, if in undercover mode, won’t reveal her name.

 public class AirlineAgent : IAgent
 {
  private string _name;
  
  public string AgentName
  {
   get { return _name;}
   set {_name = value;}
  }

  public bool accomplishMission(TimeSpan timeLimit)
  {
   // check in passengers
   // board passengers
   // prepare for departure
   // calculate time it took to complete mission
   // in this case, let's say 20 minutes
   TimeSpan totalTime = new TimeSpan(0,0,20,0,0); 
   return totalTime < timeLimit;
  }
 }

  public class SecretAgent : IAgent
  {
  private string _name;
  private bool _underCover = false;

  public string AgentName
  {
   get
   {
    if(!_underCover) return _name;
    return "";
   }
   set {_name = value;}
  }

  public bool accomplishMission(TimeSpan timeLimit)
  {
   // go to rendezvous
   // swap cash for package
   // return to base
   // calculate time it took to complete mission
   // in this case, let's say 2 days
   TimeSpan totalTime = new TimeSpan(2,0,0,0,0);
   return totalTime < timeLimit;
  }

  public void GoUndercover()
  {
   _underCover = true;
  }
 }

In projects based entirely on concrete types, you may often hear complaints about the amount of time it takes to write the unit tests. This is due to the fact that test cases are meant to exercise the methods of a type; as long as each class is defined only by its own instantiable self, then unit tests are not reusable. There is a one-to-one correlation between the classes and the test cases.

Using interfaces, though, can allow you to reuse your unit tests. When you employ this architectural strategy, you are defining a common subset of available functionality that your concrete classes can implement. Unit tests, since they target methods on a type, can be written to exercise an implementation of a given interface. For every concrete type that implements that interface, the same test case can be used to exercise and verify the methods.

To test these different agents, we will want to run tests against the public interface IAgent. Tests for accomplishMission will all be remarkably identical; test known values for timeLimit and check true or false on the return. We need to create a specific unit test for each concrete type of agent in our application, but we don’t want to rewrite the test for accomplishMission each time. Instead, start by defining a base class for your unit test that can adequately test accomplishMission:

 public class TestAgents
 {
  protected IAgent agent;
  protected TimeSpan achievableLimit;
  protected TimeSpan impossibleLimit;

  [Test]
  public void testAccomplishMission()
  { Assert.IsTrue(agent.accomplishMission(achievableLimit));
  Assert.IsFalse(agent.accomplishMission(impossibleLimit));
  }

 }

Notice that the class is not marked with [TestFixture] though it does contain at least on [Test]. TestAgents will never be instantiated directly by the NUnit test runner because you have not marked it as a TestFixture, which is precisely the behavior you want. The test method itself relies on protected fields that will be filled in by the derived tests.

 [TestFixture]
 public class TestAirlineAgent : TestAgents
 {
  [SetUp]
  public void setUp()
  {
   agent = new AirlineAgent();
   // 45 minutes
   achievableLimit = new TimeSpan(0,0,45,0,0);
   // 10 minutes
   impossibleLimit = new TimeSpan(0,0,10,0,0);
  }
 }

 [TestFixture]
 public class TestSecretAgent : TestAgents
 {
  [SetUp]
  public void setUp()
  {
   agent = new SecretAgent();
   agent.AgentName = "Jeffrey Smithers";
   //five days
   achievableLimit = new TimeSpan(5,0,0,0,0);
   //one day
   impossibleLimit = new TimeSpan(1,0,0,0,0);
  }

  [Test]
  public void TestSecretAgentName()
  {
  
   Assert.AreEqual("Jeffrey Smithers", agent.AgentName);
   SecretAgent secretAgent = (SecretAgent)agent;
   secretAgent.GoUndercover();
   Assert.AreEqual("", agent.AgentName);
  }
 }

The test for AirlineAgent is only testing the accomplishMission method, since AirlineAgent currently has no other functionality. SecretAgent, on the other hand, has the extra ability to not return its name if it is undercover. The TestSecretAgent class therefore has an extra [Test] method to cover this. The code that actually exercises accomplishMission, though, is written only once, and can be maintained and upgraded in a single place.

Define a base test class
To create a test case for NUnit, you need only define a class and mark it with the TestFixture attribute from the NUnit Framework assembly. This designation provides a marker for the test runner to identify your test cases and run them. It provides no other functionality for your class, and since it is only metadata, your class does not inherit any meaningful functionality or data from it.

However, you will find very quickly that there are techniques and strategies you employ again and again for your unit tests. It might be that you have to perform a task to set up a test data store, and run it often to clean out cruft from earlier tests, or that you have to create or destroy session information to enable proper test values. These types of repetitive activities cry out to be centrally located so that you can eliminate the extra work of typing them again and again. In keeping with the principle of “don’t repeat yourself’, it is, in fact, imperative.

The solution is to create a base test class that your specific tests can derive from. This base class will host a series of utility methods and data structures that you can call on from any individual test. In addition, if all (or even most) of your tests require some common code in setUp and tearDown, you can implement those methods on the new base class. When your individual tests require the functionality, they can call up the chain and invoke it.

For example, with our agents application, perhaps we want our unit tests to be able to validate that the agent’s name matches a certain pattern (no numbers, or if numbers, starts with “00”, or something). We would make a base class for our tests that exposes an isValidNameString method:

 public class AgentTestBase
 {
  public bool isValidNameString(string name)
  {
   // impelemnt regular expression
   // or other logic to test for name validity
  }
 }

Simply have your other tests derive from this one. In the case of our example above, we’ll have TestAgents derive from AgentTestBase, thus providing our common testing functionality to all our current tests.

Another favorite technique of mine is to make my mock objects be internal classes in the base test class. This is especially useful when I only have a few mock objects, and most of my tests can share the same versions. See “Mock the data access layer” below for an example of this.

Do not decorate the base class as a TestFixture. This just clutters your test runs with ignored tests (since it won’t have any actual [Test] methods on it).

As much as feasible, make everything return a value
This obviously isn’t a hard-and-fast, all-or-nothing rule, but as much as possible, avoid void methods and sub procedures. Unit tests are easier to write when the primary value to test is the return from a method. When a unit test has to scurry off to the database or another object or a text file to verify a simple method, then not only have you created more work for your unit test but you are also testing more than just your business logic; you are testing the infrastructure that leads from your business logic to that external data store. You are additionally adding the exact same infrastructure into your unit test, and if there is a problem, it will be a problem in the test as well as the thing being tested.

A method that returns the logical outcome of its processing can clearly enunciate its view of the world to its client, whether that be a user, other process or unit test. It may or may not reflect the true state of things, since obviously the full state of the application will probably be based on more than the code in this single method, but it will reflect what the method thinks is the state of things, which is what you should be unit testing. Testing the full application state is a job for integration testing. (For more on integration testing, see last month’s column on FitNesse).

Say that AirlineAgents have to be able to submit a timecard at the end of the day. The business rules for the application state that the agent should create the timecard, then save it to the database. Such a method might normally be written as:

public void submitTimeCard()
{
 // create timecard
 string timecard =
 string.Format("Agent Name: {0}, Date: {1}, Hours: {2}",
   _name, DateTime.Today.ToShortDateString(), "8");
 // save to db
 SqlConnection conn =
  new SqlConnection("MY_CONNECTION_STRING");
 SqlCommand comm = new SqlCommand("SOME_SQL");
 // etc.
 // ...
}

To test that, you would have to go to the database and look up the timecard and verify its format. This is open to a number of problems, and isn’t really testing the code in your method; it is testing a complex collection of activity, most of which won’t have anything to do with the agent’s ability to create the timecard.

A better way to write this method is:

public string submitTimeCard()
{
 // create timecard
 string timecard =
 string.Format("Agent Name: {0}, Date: {1}, Hours: {2}",
   _name, DateTime.Today.ToShortDateString(), "8");
 // save to db
 SqlConnection conn =
  new SqlConnection("MY_CONNECTION_STRING");
 SqlCommand comm = new SqlCommand("SOME_SQL");
 // etc.
 // ...
 return timecard;
}

Now, you can write a unit test that calls the method then verifies that the string returned matches the known state of the agent and the expected format of the document. You are not testing the database code, since that is orthogonal to the problem at hand.

So what happens if your method has more than one logical return value? If your architecture already calls for this, you will already have devised an answer to the problem. But what if you are trying to convert a void method to one with a return value (or values) just for the benefit of your unit tests? In this case, you really have three options:

pick the most relevant value and return it and nothing else
pick the most relevant value and return it as the return value of the method, but make the other values REF parameters
package all the values into a strongly typed data transfer object, which is just a fancy description of a struct
Avoid option #2 as much as possible unless your architecture specifically calls for it. Using REF parameters adds complexity to your application, and your unit tests should not force you to add complexity to your code. All of the other suggestions given in this article actually reduce complexity, which is the key to testable code.

Separate data access from business logic
Following from the last suggestion, make sure that your data access code is separated into its own layer. You might be using direct ODBC calls, or typed datasets, or an O/R mapping tool like NHibernate, but whichever method you use, make sure it lives in its own namespace and object model.

If your business objects are focused on the actual problem domain (rather than the common, and already solved, problem of storing data) then it is much easier to test whether or not you are solving the real problem. In addition, you can now implement a series of unit tests that exercise the data storage infrastructure for your application without jumping through hoops to ensure that the data you are storing is correctly formatted.

Instead of writing the timecard directly to the database inside of AirlineAgent, as in our example above, you would write a new data access class that handles saving and loading timecards.

 public class TimeCardDA
 {
  public int saveTimeCard(string timecard)
  {
   // write timecard to database
   // return new row identifier for new timecard
   // throw exception if there was an error
  }

  public string loadTimeCard(int id)
  {
   // read timecard from database
   // return timecard as string
  }
 }

The method submitTimeCard now becomes much cleaner:

public string submitTimeCard()
{
 // create timecard
 string timecard =
 string.Format("Agent Name: {0}, Date: {1}, Hours: {2}",
   _name, DateTime.Today.ToShortDateString(), "8");
 // save to db
 TimeCardDA tcda = new TimeCardDA();
 tcda.saveTimeCard(timecard);
 // ...
 return timecard;
}

In addition, now you can write unit tests that exercise just the data access layer.

 [TestFixture]
 public class TestTimeCardDA : AgentTestBase
 {
  private TimeCardDA tcda;
  private const int goodTCID = 59;
  private const int badTCID = -1;

  [SetUp]
  public void setup()
  {
   tcda = new TimeCardDA();
  }

  [Test]
  public void testLoadTC()
  {
   string timecard = tcda.loadTimeCard(goodTCID);
   Assert.IsTrue(timecard.Length > 0);
  }

  [Test]
  [ExpectedException(typeof(SqlException))]
  public void testLoadBadTC()
  {
   string timecard = tcda.loadTimeCard(badTCID);
  }

  // etc.
 }

Mock the data layer to test the business logic

When you are writing the unit tests that target the domain logic, mock the data access layer to ensure the separation of concerns. Just because you have separated the data access code into is own namespace, if the business logic is inseparably dependent on it, you still have the same problem: testing the business logic is dependent on successful data access logic.

You can either choose to create your own mock data access classes, or employ a mock object framework like nmock. We’ll save mock-object frameworks for another column. Today, let’s just create a mock version of TimeCardDA that throws exceptions when it is given a well-known input.

 public class MockTimeCardDA : TimeCardDA
 {
  public const string badtimecard = "BADTIMECARD";
  public const int newTCID = 60;

  public override int saveTimeCard(string timecard)
  {
   if(timecard.Equals(badtimecard))
    throw new Exception("BAD TIME CARD");
   return newTCID;
  }

  public override string loadTimeCard(int id)
  {
   if(id < 0)
    throw new Exception("BAD TIME CARD ID");
   return string.Format("Agent Name: {0},
    Date: {1}, Hours: {2}", "John Doe", DateTime.Today.ToShortDateString(), "8");

  }
 }

This mock version of the data access defines some well-known error-inducing inputs. If the input is anything other than the defined error procuring values, then the methods will return something resembling a real value. When the well-known input is given, the method will error out.

Make use of configuration
If you have followed the advice given so far, then you have an architecture based on interface implementation, with a variety of concrete implementations of your code. Multiple domain objects implementing the same interface, separated domain and persistence layers, and a variety of mock or test objects that can be used in place of the real thing. In order to make full use of all of this, you need to take advantage of the configuration abilities of .NET.

Let’s examine the case of the persistence layer. For normal use, your domain model will rely on the real data access layer to perform its data storage. During testing, though, you will want to use the mock persistence layer. If your domain model is tightly coupled to the real persistence layer, then you will not be able to easily replace it at test-time.

Instead of making the domain model directly coupled to the persistence model, employ the indirection pattern. Create some kind of broker or router that your domain model relies on to provide concrete implementations of the persistence layer. This broker will look up the classes that are needed for the storage operations and create instances of those classes reflectively, based on the values in the configuration file. When the application is deployed, it will have a configuration file pointing to all of your real persistence classes. The test environment, though, should have its own copy of the configuration that points to your mock data object layer.

For our agents application, we’ll want to have a way to get the real version of the TimeCardDA in a deployment scenario, but the mock version for unit testing. First, let’s add a configuration element to the .config file for our application:

<appSettings>
 <key name="TimeCardDA" value="tensteps.TimeCardDA"/>
</appSettings>

Next, we’ll modify TimeCardDA so that you cannot instantiate it directly. Instead, we’ll use the factory pattern (calling a static method on the class to return a new instance). The static method will look in the configuration file to determine whether to return the real or mock object.

public class TimeCardDA
{
 protected TimeCardDA()
 {
 }

 public static TimeCardDA newInstance()
 {
  string version =
  System.Configuration.ConfigurationSettings.AppSettings["TimeCardDA"];
  return (TimeCardDA)typeof(TimeCardDA).Assembly.CreateInstance("ninesteps.MockTimeCardDA");
  }

// etc.

Finally, we need only change our code to use the new factory method instead of the direct constructor.

public string submitTimeCard()
{
 // create timecard
 string timecard =
 string.Format("Agent Name: {0}, Date: {1}, Hours: {2}",
 _name, DateTime.Today.ToShortDateString(), "8");
 
 // save to db
 TimeCardDA tcda = TimeCardDA.newInstance();
 tcda.saveTimeCard(timecard);
 // etc.
 return timecard;
}

Now, whenever we run the unit test suite, we make sure that the value of the TimeCardDA key in the config file is set to the mock object instead of the real, and our unit tests will test only the logic of the business model.

You could, instead, implement a method or property on the domain objects that tell it whether or not to use the real mock object.

[TestFixture]
public class TestAirlineAgent : TestAgents
{
 [SetUp]
 public void setUp()
 {
  agent = new AirlineAgent();
  agent.useMockDA(); ]
  // etc.

This makes it very explicit from the test code’s perspective what is being tested; nobody reading your tests will miss the fact that the data generated during the test will be sent off to some mock objects instead of the real thing. However, it means that your domain objects have to implement some code that is ONLY useful during testing, and this is usually a bad idea. Your domain objects should be devoted to the single purpose of solving your business problem; extraneous testing-specific code at best clutters the interface, and at worst, can have unintended ripple-effects throughout the class and possibly the rest of the code.

Make Your Classes Do Only One Thing
This is a fairly common design principle that deserves its own point. When you write a class, it is the domain model representation of some idea. Too often, we clutter these classes with code that is only tangentially related to the idea. In “Separate data access from business logic”, we examined one of the many ways that programmers clutter their code with extraneous functionality.

The rule of thumb is that there should only ever be one reason for you to modify a class. If you find yourself going back to the class to make changes again and again as different requirements change, then the class is probably overcrowded. When this happens, determine what the class was intended to do, and refactor everything else into one or more other classes. If our SecretAgent class was spending too much time in file i/o, or the AirlineAgent kept looking things up via LDAP, then we would want to remove that non-core logic and put it in another class dedicated to that kind of task.

Have Domain Object Factories
Often, the unit of functionality that you are testing is dependent on other parts of your domain model. In general, you will not want to use mock objects to impersonate the objects your functionality relies on. Mock objects are generally used to impersonate external objects from third-party libraries whose internal state you cannot control nor directly observe.

Your domain objects might have very convoluted construction requirements. If the object needs more than a single call to a simple constructor to be initialized into a state that is useful for your test, you should think about creating a test factory for that class. The test factory should provide a static method for returning an instance of the class in a ready state for use in your tests. On top of that, it should provide some static constants defining known property values that can be used to verify the state during your tests.

For example, we might need to create a series of SecretAgents for testing. We will want to create them in known states with known values. Here is a sample factory for SecretAgents:

public class TestSecretAgentFactory
{
 public static const string GOOD_AGENT_NAME =
  "Jeffrey Smithers";
 public static const string BAD_AGENT_NAME = "!@#$";
  
 public static IAgent CreateGoodAgent()
 {
  SecretAgent agent = new SecretAgent();
  agent.AgentName = GOOD_AGENT_NAME;
  return agent;
 }

 public static IAgent CreateBadAgent()
 {
  SecretAgent agent = new SecretAgent();
  agent.AgentName = BAD_AGENT_NAME;
  return agent;
 }

 public static IAgent CreateUndercoverAgent()
 {
  SecretAgent agent = new SecretAgent();
  agent.AgentName = GOOD_AGENT_NAME;
  agent.GoUndercover();
  return agent;
 }
}

Whenever one of your tests needs to introduce a SecretAgent into the test, perhaps passing one or more into a method that operates on a collection of IAgents, then you can use the factory to create them. Moreover, when you are handed back a reference to an IAgent in the course of a test, you can compare its data values against known values on the test factory.

Think carefully about packaging, assemblies and namespaces
Eventually, almost all “enterprise level” applications will grow to the point that running the entire suite of unit tests becomes a severe burden on the development team. Since running unit tests often is one of the central tenets of agile development (and it really is a good idea) this problem can quickly lead to fewer runs of the tests (and at worst, fewer tests written).

One way to avoid this problem is to plan your application for natural divisions of the codebase. Instead of allowing everything to be part of one monolithic assembly, the application should be built around the idea of multiple, interrelated assemblies. Your tests should follow the same architectural separation. When you work on a specific piece of the application, you can focus on running the tests associated with the assembly you are knee-deep in, and ignore the rest.

Don’t be afraid of multiply-nested namespaces. If your application naturally breaks down in a nested tree structure, then let it. The only strong rule for breaking your application up into multiple assemblies and namespaces is to be careful not to overly entwine them. You generally only want dependencies running one direction between any two packages. If classes in one assembly are dependent on classes in a second, the reverse should not be true. This will allow you to replace entire assemblies more easily (for instance, if all your persistence code lives in its own assembly, you could swap it out for a new assembly that targets a different database, or one composed entirely of mock objects).

Pick a logging strategy early
Even given the earlier recommendation to have your methods return values, sometimes you can’t test everything you need to just by examining the return from a method. Since unit tests are usually run from outside your development environment, it makes step through debugging during testing difficult. In truth, most unit tests are run as batches anyways, and even if you could step into the code, you won’t be sitting there and be able to.

What you need is an external store of application state that you can examine and correlate back to the test results. You need a logging strategy. It is vital to implement your chosen logging strategy as early as possible in the development effort, so that you don’t have to layer it back into existing code later.

Beyond that, logging will be enormously beneficial to your application post-deployment. Since bugs are difficult enough to trace when you have a full development environment available to you, tracing bugs at the customer site is next to impossible. Detailed logging allows you, and your customer, to get a detailed look at application state in both a real-time and historical perspective.

You may choose to use the built-in Trace mechanism in the FCL, or move to an external tool like log4net. Regardless, make sure you learn the basics of categorizing your messages, sorting by priority and, most importantly, routing them to different output stores. The console is a great place to get realtime logging information, but what happens when your unit tests run as a batch overnight? Where is the console tomorrow? You need to be able to store the log information in files or data tables for retrieval and examination later.

Summary
This is by no means an exhaustive treatment on the testability of applications. Entire articles can be written just about the testability of user interfaces and data access layers. Instead, these ten suggestions form a good starting point for re-examining the assumptions inherent in your design, and thinking through the decisions that will affect your code’s testability. Since testability determines how well you can verify your application, it should follow that a testable application is a better application.


Authors
 Justin Gehtland is a founding member of Relevance, LLC, a consultant group dedicated to elevating the practice of software development. He is the co-author of Windows Forms Programming in Visual Basic .NET (Addison Wesley, 2003) and Effective Visual Basic (Addison Wesley, 2001). Justin is an industry speaker, and instructor with DevelopMentor in the .NET curriculum.

CodeLib .NET (Access) 10.6 10.6版是最后一个免费的版本了, CodeLib 是整合 文章/源代码/文件/图片/网页/网址 保存管理六合一的一款优秀的档案管理, 能够方便的进行资料的全文检索. 立即下载

相关推荐

通过Linq操作Sql Server数据库

基本的通过Linq对数据库进行增删查改,很适合初学linq的人员

10 ways to make your code more Testable

IntroductionYou know you have to write unit tests. You have the tools, and your team is committed to the idea. Somehow, though, despite your best intentions, the tests just never get written. Or you

天道酬勤 2000

两路半桥LLC谐振变换器软开关Simulink仿真(模拟谐振参数不同、分裂电容)

内容概要:本文介绍了“两路半桥LLC谐振变换器软开关Simulink仿真”资源包,重点在于基于Simulink平台对两路半桥LLC谐振变换器进行高精度建模与动态仿真,特别考虑了谐振参数不一致及分裂电容等非理想工况对系统性能的影响。该仿真模型不仅涵盖了主电路拓扑、软开关实现机制与谐振网络设计,还深入分析了不同参数配置下系统的启动特性、稳态效率、动态响应及软开关条件的满足情况。通过参数扫描与对比仿真,帮助用户掌握LLC变换器的关键设计要素与优化方法,具备较强的工程指导价值和科研教学意义。; 适合人群:电力电子、电气工程及其自动化等相关专业的高校师生,以及从事高频开关电源、新能源变换器、车载充电机等领域的研发工程师和技术人员。; 使用场景及目标:① 掌握两路并联半桥LLC谐振变换器的建模与仿真方法;② 理解软开关技术在提升变换器效率与降低EMI方面的关键作用;③ 分析谐振参数偏差与分裂电容结构对系统均流特性、增益曲线及软开关范围的影响;④ 支持科研项目中的拓扑验证、控制策略开发与故障工况分析; 阅读建议:建议结合Simulink仿真模型与配套说明文档进行学习,重点关注谐振腔参数设置、驱动时序设计及软开关波形观测;可通过调整谐振电感、电容值或引入参数失配,观察系统行为变化,深入理解LLC变换器的稳定边界与优化设计原则。

如何编写可测试的代码 哈利勒的方法论

Understanding how to write testable code is one of the biggest frustrations I had when I finished school and started working at my first real-world job. 当我完成学业并开始从事第一份现实世界的工作时,了解如何编写可测试的代码是我最大的挫败之一。 ...

360

揭秘cocos-mcp:如何用AI助手提升CocosCreator游戏开发效率

本文深入介绍了cocos-mcp工具,它作为连接AI助手与CocosCreator编辑器的桥梁,遵循MCP协议,能显著提升游戏开发效率。通过自然语言指令,开发者可让AI直接查询场景结构、批量修改属性或生成上下文代码,将重复操作变为智能调度,实现从“手动操作者”到“指令指挥官”的工作流变革。

weixin_29001683的博客 1053

CentOS7.9 安装 ImageMagick,图片转换为HEIC图像格式

由于ImageMagick7以下不支持heic等图片格式,所以重新安装了ImageMagick7.1版本支持heic格式,在网上找了很多资料,归纳总结并写此文章记录一下。在Linux(CentOS7.9)上安装ImageMagick7.1.1-38。

shmily_i的博客 1941

运维:你们 JAVA 服务怎么又又又又出问题了(1)

而且这些线程池没有任务需要执行的话,线程肯定是 WAITING 状态,也不会占用 CPU 的利用率,负载有不会有影响。不过如果这里直接 stack ThreadPoolExecutor#execute 方法的话,干扰信息可能太多了,毕竟调用 execute 的地方太多,不好抓到重点 ​。所以这个问题,肯定是哪个小天才,在代码里每次都新建线程池,然后还不 shutdown 导致的!习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Linux运维知识点,真正体系化!

2401_84140384的博客 810

拆解大疆M300电池BMS:基于TI TIDA-010030方案的硬件架构深度分析

本文深度解析了大疆M300无人机电池管理系统(BMS)基于TI TIDA-010030参考设计的硬件架构。通过对比TI方案与大疆实现的差异,详细介绍了BQ7694003监控前端和BQ34Z100电量计的优化设计,以及通信架构的可靠性改进。文章还揭示了大疆在成本、空间和标准化方面的工程妥协与创新平衡,为锂电池保护方案提供了实践参考。

weixin_27066963的博客 239

10 ways to make your code more testable

[By Justin Gehtland] Introduction You know you have to write unit tests. You have the tools, and your team is committed to the idea. Somehow, though, despite your best intentions, the tests just nev...

weixin_34315189的博客 149

STM32控制气泵和电磁阀实现

2、mos管的选型:mos管选择主要注意两个参数即可,一是导通的电流,二是耐压值,并且常用NMOS管,根据要求,气泵和电磁阀供电电压为12V,所以选择的mos管耐压值要大于12V,这里选用耐压值为30V的MOS管,并且导通电流为5.8A,如下图。1、气泵和电磁阀的开和关均为开关量,实现控制方法有多种,比如继电器,但是继电器动作有噪声且体积较大,更好的方法为使用mos管。使用STM32控制气泵和电磁阀的开和关,气泵和电磁阀的供电电压为12V。最终实现单片机控制气泵和电磁阀的开和关。

jacklood的博客 1万+

stm32H743IIT6 cubemx HAL USB UVC摄像头基础

stm32性能已经很强了, 可以驱动ov5640摄像头, 所以可以把摄像头接在stm32上, 当作一个摄像头驱动器, 连接到电脑上 开发环境: stm32cubemx 6.0.1 单片机: 自己做的stm32h743iit6核心板,兼容正点原子 学习资料: 圈圈学USB 鱼鹰谈单片机 从零开始学习USBhttps://to-run-away.blog.youkuaiyun.com/article/details/85038393 整个项目是基于CDC串口上修改 1 stm32 USB 代码概览 ..

紫枫洛天的博客 7754

Writing Testable Code: A Journey Through Consideration and Refactoring

【代码】Writing Testable Code: A Journey Through Consideration and Refactoring。

u012333203的博客 1078

Claude Code Router 401错误修复

claude code router配置相关环境变量问题

如沐春风 6364

谷歌数据科学面试备战:用ChatGPT构建认知校准系统

数据科学面试本质是考察统计直觉、工程权衡与产品思维的综合能力,而非知识点复述。其核心原理在于将抽象概念(如AB实验、指标设计)转化为可验证的业务决策路径,并通过结构化反馈实现能力跃迁。技术价值体现在打破传统刷题的断层式学习,以‘问题类型×考察维度×难度标尺’三维框架驱动精准提升。典型应用场景包括DAU归因诊断、YouTube粘性指标设计、SQL性能校准等谷歌真实任务。本文聚焦如何将ChatGPT从答案生成器重构为具备Level感知能力的认知校准器,深度融合统计推断与工程化思维。

dibeichan3033的博客 366

XDMA Scatter-Gather(SG)模式

XDMA Scatter-Gather(SG)模式 是 Xilinx FPGA 中用于高效处理 ​非连续内存数据 的 DMA 传输机制,通过 ​描述符链表(Descriptor List)​ 管理多块分散数据,显著减少 CPU 开销并提升吞吐量。

浩瀚之水的专栏 2149

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

【Arthas】使用trace命令时出现No class or method is affected, try:

Arthas使用trace命令时出现No class or method is affected, try:的解决方法

Brill_y的博客 1454

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

使用Arthas排查性能问题

记使用Arthas排查性能问题

Keep learing, and stay fast 3287

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

利用JVM在线调试工具排查线上问题

利用JVM在线调试工具排查线上问题 在生产上我们经常会碰到一些不好排查的问题,例如线程安全问题,用最简单的threaddump或者heapdump不好查到问题原因。为了排查这些问题,有时我们会临时加一些日志,比如在一些关键的函数里打印出入参,然后重新打包发布,如果打了日志还是没找到问题,继续加日志,重新打包发布。对于上线流程复杂而且审核比较严的公司,从改代码到上线需要层层的流转,会大大影响问题排查的进度。 这个时候我们可以使用能够在线调试的工具帮助我们查找问题,例如btrace,可以动态的插入代码,极大

simba_1986的专栏 873

【Blog.Idp开源】支持在线密码找回

(一个做认证平台,必须会遇到的一个问题)BCVP框架,是基于:ASP.NETCore5.0+VUE.js+IdentityServer4等核心技术,实现的前后端分离与动态认证鉴权一体化平台...

dotNET跨平台 404

利用arthas实时定位线上性能问题

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_33701617的博客 3169

微信环境下获取code、access_token和openid

//获取code getCode () function getCode() { var code = GetRequest()['code']; var local = window.location.href; if (code == null || code === '') { window.location.href = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid=' + windo.

weixin_38242636的博客 1039

新建共享,NTFS权限设置

1. Overview   Some time ago, I was automating a few tasks with PowerShell and needed to set NTFS permissions on a folder. I was tempted to use the good old ICACLS.EXE command line, but I wanted to k...

weixin_34345753的博客 348
上一篇: 用VC写Assembly代码(4)
下一篇: 用VC写Assembly代码(5) --字符串
普通网友
博客等级 码龄22年 1万+粉丝 3156原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值